⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 缓冲溢出原理.doc

📁 介绍缓冲溢出的原理
💻 DOC
📖 第 1 页 / 共 5 页
字号:
  lang=EN-US>(prolog)工作. 当例程退出时, 堆栈必须被清除干净, 这称为例程的收尾</span></pre><pre><span
  lang=EN-US>(epilog)工作. Intel的ENTER和LEAVE指令, Motorola的LINK和UNLINK指令, 都可以用于</span></pre><pre>有效地序幕和收尾工作<span
  lang=EN-US>.</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>下面我们用一个简单的例子来展示堆栈的模样:</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span></span></pre><pre><span
  lang=EN-US>example1.c:</span></pre><pre><span lang=EN-US>------------------------------------------------------------------------------</span></pre><pre><span
  lang=EN-US>void function(int a, int b, int c) {</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>char buffer1[5];</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>char buffer2[10];</span></pre><pre><span
  lang=EN-US>}</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US>void main() {</span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp; </span>function(1,2,3);</span></pre><pre><span
  lang=EN-US>}</span></pre><pre><span lang=EN-US>------------------------------------------------------------------------------<span style='mso-spacerun:yes'>&nbsp; </span></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;</span></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;</span>为了理解程序在调用function()时都做了哪些事情, 我们使用gcc的-S选项编译, 以产</span></pre><pre>生汇编代码输出<span
  lang=EN-US>:</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US>$ gcc -S -o example1.s example1.c</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>通过查看汇编语言输出, 我们看到对function()的调用被翻译成:</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>pushl $3</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>pushl $2</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>pushl $1</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>call function</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp; </span></span></pre><pre
  style='margin-left:-1.8pt;mso-para-margin-left:-.15gd'><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;</span>以从后往前的顺序将function的三个参数压入<span
  class=GramE>栈</span>中, 然后调用function(). 指令call</span></pre><pre
  style='margin-left:-1.8pt;mso-para-margin-left:-.15gd'>会把指令指针<span
  lang=EN-US>(IP)也压入栈中. 我们把这被保存的IP称为返回地址(RET). 在函数中所做</span></pre><pre>的第一件事情是例程的序幕工作<span
  lang=EN-US>:</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>pushl %ebp</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>movl %esp,%ebp</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>subl $20,%esp</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>将帧指针EBP压入栈中. 然后把当前的SP复制到EBP, 使其成为新的帧指针. 我们把这</span></pre><pre>个被保存的<span
  lang=EN-US>FP叫做SFP. 接下来将SP的值减小, 为局部变量保留空间.</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>我们必须牢记</span><span
  lang=EN-US style='font-family:黑体'>:内存只能以字为单位寻址. 在这里一个字是4个字节</span><span
  lang=EN-US>, 32位. 因此5字节</span></pre><pre>的缓冲区会占用<span lang=EN-US>8个字节(2个字)的内存空间, 而10个字节的缓冲区会占用12个字节(3个字)</span></pre><pre>的内存空间<span
  lang=EN-US>. 这就是为什么SP要减掉20的原因. 这样我们就可以想象function()被调用时</span></pre><pre>堆栈的模样<span
  lang=EN-US>(每个空格代表一个字节):</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre>内存低地址<span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp; </span><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>内存高地址</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>buffer2<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>buffer1<span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>sfp<span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>ret<span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>a<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp; </span>b<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp; </span>c</span></pre><pre><span
  lang=EN-US>&lt;------<span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>[<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>][<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>][<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>][<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>][<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>][<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>][<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>]</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;</span></span></pre><pre>堆栈顶部<span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>堆栈底部</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>缓冲区溢出</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>~~~~~~~~~~~~</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>缓冲区溢出是向一个缓冲区填充超过它处理能力的数据所造成的结果. 如何利用这个</span></pre><pre>经常出现的编程错误来执行任意代码呢<span
  lang=EN-US>? 让我们来看看另一个例子:</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US>example2.c</span></pre><pre><span lang=EN-US>------------------------------------------------------------------------------</span></pre><pre><span
  lang=EN-US>void function(char *str) {</span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>char buffer[16];</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>strcpy(buffer,str);</span></pre><pre><span
  lang=EN-US>}</span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span
  lang=EN-US>void main() {</span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp; </span>char large_string[256];</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp; </span>int i;</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp; </span>for( i = 0; i &lt; 255; i++)</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>large_string[i] = 'A';</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp; </span>function(large_string);</span></pre><pre><span
  lang=EN-US>}</span></pre><pre><span lang=EN-US>------------------------------------------------------------------------------</span></pre><pre><span
  lang=EN-US> </span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;</span>这个程序的函数含有一个典型的内存缓冲区编码错误. 该函数没有进行边界检查就复</span></pre><pre><span
  class=GramE>制提供</span>的字符串<span lang=EN-US>, 错误地使用了strcpy()而没有使用strncpy(). 如果你运行这个程序就</span></pre><pre>会产生<span
  class=GramE>段错误</span><span lang=EN-US>. 让我们看看在调用函数时堆栈的模样:</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre>内存低地址<span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>内存高地址</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>buffer<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>sfp<span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>ret<span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>*str</span></pre><pre><span
  lang=EN-US>&lt;------<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>[<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>][<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>][<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>][<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>]<span style='mso-spacerun:yes'>&nbsp; </span><span style='mso-spacerun:yes'>&nbsp;</span></span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre>堆栈顶部<span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>堆栈底部</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>这里发生了什么事? 为什么我们得到一个<span
  class=GramE>段错误</span>? 答案很简单: strcpy()将*str的</span></pre><pre>内容<span
  lang=EN-US>(larger_string[])复制到buffer[]里, 直到在字符串中碰到一个空字符. 显然, </span></pre><pre><span
  lang=EN-US>buffer[]比*str小很多. buffer[]只有16个字节长, 而我们却试图向里面填入256个字节</span></pre><pre>的内容<span
  lang=EN-US>. 这意味着在buffer之后, 堆栈中250个字节全被覆盖. 包括SFP, RET, 甚至*str!</span></pre><pre>我们已经把<span
  lang=EN-US>large_string全都填成了A. A的十六进制值为0x41. 这意味着现在的返回地</span></pre><pre>址是<span
  lang=EN-US>0x41414141. 这已经在进程的地址空间之外了. 当函数返回时, 程序试图读取返回</span></pre><pre>地址的下一个指令<span
  lang=EN-US>, 此时我们就得到一个<span class=GramE>段错误</span>.</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>因此缓冲区溢出允许我们更改函数的返回地址. 这样我们就可以改变程序的执行流程.</span></pre><pre>现在回到第一个例子<span
  lang=EN-US>, 回忆当时堆栈的模样: </span></pre><pre><span lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre>内存低地址<span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>内存高地址</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>buffer2<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>buffer1<span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>sfp<span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>ret<span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>a<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp; </span>b<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp; </span>c</span></pre><pre><span
  lang=EN-US>&lt;------<span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>[<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>][<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>][<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>][<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>][<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>][<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>][<span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>]</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></pre><pre>堆栈顶部<span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>堆栈底部</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp;&nbsp; </span>现在试着修改我们第一个例子, 让它可以覆盖返回地址, 而且使它可以执行任意代码.</span></pre><pre>堆栈中在<span
  lang=EN-US>buffer1[]之前的是SFP, SFP之前是返回地址. ret从buffer1[]的结尾算起是4个</span></pre><pre>字节<span
  lang=EN-US>.应该记住的是buffer1[]实际上是2个字即8个字节长. 因此返回地址从buffer1[]的开</span></pre><pre>头算起是<span
  lang=EN-US>12个字节. 我们会使用这种方法修改返回地址, 跳过函数调用后面的赋值语句</span></pre><pre><span
  lang=EN-US>'x=1;', 为了做到这一点我们把返回地址加上8个字节. 代码看起来是这样的:</span></pre><pre><span
  lang=EN-US><o:p>&nbsp;</o:p></span></pre><pre><span lang=EN-US>example3.c:</span></pre><pre><span
  lang=EN-US>------------------------------------------------------------------------------</span></pre><pre><span
  lang=EN-US>void function(int a, int b, int c) {</span></pre><pre><span
  lang=EN-US><span style='mso-spacerun:yes'>&nbsp;&nbsp; </span>char buffer1[5];</span></pre><pre><span

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -