栈溢出笔记1.1 函数调用过程

选择从栈溢出开始学习Shellcode的编写,是因为在没有保护机制(栈Cookie,ASLR,DEP,SafeSEH)的系统中使用栈溢出是一件很简单的事情。栈区随着函数调用动态变化,每个函数调用时在栈上占用的空间称为栈帧。用一个示例来说明栈上保存的内容及动态变化的过程。

下面是一个程序,生成一个对话框显示一条“Hello World!”消息。下面是该程序的C代码:

在VS2008中用Debug版编译之后,拖入Immunity Debugger中:

图1 example_1.exe入口点

与用汇编直接编写的程序不同,VS在真正进入main函数之前加入了很多其它的代码,入口点停在了一条跳转指令上(如图1),因此,需要找到真实的main函数。调试别的软件时由于不知道具体细节,需要跟踪判断以及一些特殊方法。但由于是我们自己编写的程序,就不用了,直接“bp MessageBoxA”在MessageBoxA函数下断点,然后使用回溯法,即可快速找到main函数。下面是真实的main函数:

图2 真正的main函数入口

这里可以看到调用MessageBoxA函数。

我们要跟踪函数MessageBoxA的调用过程,在004113C0的PUSH 0指令处下断点。Windows API函数的调用方式为stdcall,即参数从右向左入栈,被调用者负责清栈。MessageBoxA函数来自于user32.dll,函数原型如下:

/*********************************************************/
int WINAPI MessageBoxA(
  _In_opt_ HWND    hWnd,
  _In_opt_ LPCTSTR lpText,
  _In_opt_ LPCTSTR lpCaption,
  _In_     UINT    uType
);
/*********************************************************/

示例example_1中调用所给的参数如下:

/*********************************************************/
MessageBox( NULL, "HelloWorld", "example_1", MB_OK );
/*********************************************************/

从在004113C0的PUSH 0开始的四条PUSH语句,就是参数的入栈过程。

执行PUSH 0之前,先记一下当前栈的内容:

图3

下面执行四条PUSH语句,直到CALL处停住,看栈的内容:

图4

看到参数从右向左都已入栈。

下面是CALL语句,按F7跟踪进函数MessageBoxA,注意栈的变化:

图5

执行PUSH EBP之前,看当前栈:

图6

栈上多了一个值:004113D4,这个值正是CALL MessageBoxA下一条语句的地址(见图2),这正是CALL指令的作用。将下一条指令(返回地址)入栈,然后跳转到函数执行。这个地址是栈溢出利用的重点,因为它在函数返回的时刻将被放入EIP,作为指令地址。

下面接着执行MessageBoxA函数中的下一条指令PUSH EBP。下面两条指令:

/*********************************************************/
PUSH EBP
MOV EBP, ESP
/*********************************************************/

标志着函数栈帧的建立,也就是说,函数现在开始接手栈,它开始圈出自己的一块地(开辟新的栈基址EBP和栈范围ESP),使用这一块地来保存自己的局部变量,保存自己的信息。函数RET 之前还有POP EBP,表示函数自己的栈帧使用完了,可以清理掉了。因此,在调用函数的过程中,栈内容分布如下:

图7

函数返回的过程不再跟踪。下面看图7,开始说栈溢出的内容。

前面说到函数在栈上开辟自己的栈帧,用来保存自己的变量,正常情况下,函数应该使用它自己圈出来的地(栈帧),而不应该越界,因为一旦它越界,就会破坏调用者保存在栈上的内容(返回地址,参数,以及调用者的局部变量等)。调用者所保存的这些内容中有一个最重要的内容:返回地址,因为它控制着程序的流程,一旦它被破坏,程序就不再受调用者控制(再也回不到调用者指令流程中了)。因此,一旦有栈溢出漏洞,黑客们就可能利用它来控制程序流程,做坏事。

时间: 2024-08-01 16:00:17

栈溢出笔记1.1 函数调用过程的相关文章

函数调用过程&生成器解释

摘自马哥解答,感谢. 函数调用过程: 假设程序是单进程,单执行流,在某一时刻,能运行的程序流只能有一个.但函数调用会打开新的执行上下文,因此,为了确保main函数可以恢复现场,在main函数调用其它函数时,需要先把main现场保存下来,放一边,即栈中.这时候,被调用函数即可执行,且完成后,可加到调用者Main.“回到”调用者main,main就可以继续向后运行. 函数调用可嵌套运行,例如,X --> Y --> Z, 在Z返回后,Y方可继续,并直到返回,接着X才能继续, 并直到结束.此场景中,

c函数调用过程原理及函数栈帧分析

转载自地址:http://blog.csdn.net/zsy2020314/article/details/9429707       今天突然想分析一下函数在相互调用过程中栈帧的变化,还是想尽量以比较清晰的思路把这一过程描述出来,关于c函数调用原理的理解是很重要的. 1.关于栈 首先必须明确一点也是非常重要的一点,栈是向下生长的,所谓向下生长是指从内存高地址->低地址的路径延伸,那么就很明显了,栈有栈底和栈顶,那么栈顶的地址要比栈底低.对x86体系的CPU而言,其中 ---> 寄存器ebp(

C++函数调用过程深入分析<转>

转自http://blog.csdn.net/dongtingzhizi/article/details/6680050 C++函数调用过程深入分析 作者:靠谱哥 微博:洞庭之子-Bing 0. 引言 函数调用的过程实际上也就是一个中断的过程,那么C++中到底是怎样实现一个函数的调用的呢?参数入栈.函数跳转.保护现场.回复现场等又是怎样实现的呢?本文将对函数调用的过程进行深入的分析和详细解释,并在VC 6.0环境下进行演示.分析不到位或者存在错误的地方请批评指正,请与作者联系. 首先对三个常用的

深入理解C语言的函数调用过程 【转】

转自:http://blog.chinaunix.net/uid-25909619-id-4240084.html 原文地址:深入理解C语言的函数调用过程 作者:wjlkoorey258 本文主要从进程栈空间的层面复习一下C语言中函数调用的具体过程,以加深对一些基础知识的理解.    先看一个最简单的程序: 点击(此处)折叠或打开 /*test.c*/ #include <stdio.h> int foo1(int m,int n,int p) { int x = m + n + p; ret

swift 笔记 (十四) —— 构造过程

构造过程 为了生成类.结构体.枚举等的实例,而做的准备过程,叫做构造过程. 为了这个过程,我们通常会定义一个方法来完成,这个方法叫做构造器.当然它的逆过程,叫做析构器,用于在实例被释放前做一些清理工作以及一此自定义化的处理. 为存储型属性设置初始值 类和结构体在生成实例那一刻,必须为所有的属性赋以特定的初始值. 要么在定义存储型属性的时候直接给个初始值,否则就必须在构造器里面指定一个初始值. 上面说的这两种情况,都不会触发存储型属性的监听者行为(property observer). struc

ARM系统中函数调用过程中的参数传递-转

在 嵌入式软件编程中,经常会用到函数调用,之前在学习如何在C语言中嵌入汇编时有了解到C语言之前的参数调用是使用寄存器R0传递第一个参数,R1传递到第 二个..一直到R3传递第四个参数.但是实际上有时可能传递的参数非常多,超过8个,或是参数中有浮点数之类,参数也会超过4个寄存器,对于超出的部份并 不使用R4,而是使用堆栈的方式,但具体是如何的方式很多网站就没了下文了. 对于ARM体系来说,不同语言撰写的函数之间相互调用(mix calls)遵循的是 ATPCS(ARM-Thumb Procedur

(转)函数调用过程探究

转自:http://www.cnblogs.com/bangerlee/archive/2012/05/22/2508772.html 引言 如何定义函数.调用函数,是每个程序员学习编程的入门课.调用函数(caller)向被调函数(callee)传入参数,被调函数返回结果,看似简单的过程,其实CPU和系统内核在背后做了很多工作.下面我们通过反汇编工具,来看函数调用的底层实现. 基础知识 我们先来看几个概念,这有助于理解后面反汇编的输出结果. 栈(stack) 栈,相信大家都十分熟悉,push/p

09 js函数调用过程内存分析、js函数细节

函数的调用过程 Js函数调用过程的内存分析. 一个递归调用的例子: <html> <head> <script> //abc是一个函数它接收一个数值 function abc(num1){ if (num1>3) { abc(--num1); //递归 } document.writeln(num1); } abc(5); </script> </head> <body> </body> </html>

oracle学习笔记 SQL语句执行过程剖析讲课

oracle学习笔记 SQL语句执行过程剖析讲课 这节课通过讲述一条SQL语句进入数据库 和其在数据库中的整个的执行过程 把数据库里面的体系结构串一下. 让大家再进一步了解oracle数据库里面的各个进程.存储结构以及内存结构的关联关系. 首先来讲整个体系中有客户端.实例和数据库 数据库里有三类文件 控制文件ctl.数据文件dbf.日志文件log 实例中SGA有六大池子 第一大内存区shared pool即共享池 第二大内存区buffer cache 第三块是redo log 我们主要讲上面的三