函数栈解析.docx

  1. 1、本文档共7页,可阅读全部内容。
  2. 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
  3. 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  4. 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
函数栈解析

本文将对函数栈进行解析,在此之前先对程序的内存分配有个大概了解。程序内存逻辑分配一个程序中内存分布如下图:代码段:保存程序文本,可读可执行不可写,指令寄存器EIP指向代码段中将要执行的代码行首地址数据段:保存已初始化的全局变量和静态变量,可读可写不可执行BBS:未初始化的全局变量和静态变量Heap(堆):动态内存,数据存放向内存高端增长,可读可写可执行Stack(栈):存放局部变量,函数参数,函数调用信息,寄存器状态等,函数栈便是在栈区,数据存放向内存低端增长,可读可写可执行简单介绍下几个常用的寄存器通用寄存器:EAX:累加寄存器。用于算术运算的主要寄存器,也常用来存放函数的返回值。在保护模式下也可作为内存偏移指针。ECX:计数器寄存器。常用于特定指令的计数。EBX:基地址寄存器。内存寻址时用于存放基地址。EDX:多功能寄存器。常用于乘除法和I/0指针。ESI:源变址寄存器。通常在内存操作指令中作为“源地址指针”使用。EDI:目的变址寄存器。通常在内存操作指令中作为“目的地址指针”使用。ESP:栈指针。作为指针指向当前栈的栈顶(栈顶为栈的低地址)。EBP:帧指针。作为指针指向当前栈的栈底(栈底为栈的高地址)。EIP:指令寄存器。作为指针指向下一条指令,该寄存器的值不能直接修改。函数栈解析:本文将以一个示例程序对函数栈进行解析:#includestdio.h#includeWindows.hint Fun(inta, intb){returna + b;}int main(){int a, b;a = 0b = 0Fun(3, 4);system(pause nul);return 0;}函数栈初始化下面以main函数的函数栈为例介绍函数栈的初始化:main函数初始化在VS下的反汇编源码如下:14: int main()15: {001D1410pushebp001D1411movebp, esp001D1413subesp, 0D8h001D1419pushebx001D141Apushesi001D141Bpushedi001D141Cleaedi, [ebp – 0D8h]001D1422movecx, 36h001D1427moveax, 0CCCCCCCCh001D142Crep stosdword ptr es : [edi]包括调用main函数,每个函数栈的初始化都是相似的。被调用函数会先将各状态寄存器和堆栈寄存器压栈,完成对原始寄存器状态的保存;并分配函数栈的大小并初始化函数栈。接下来对每行汇编源码进行分析:push ebp、ebx、esi、edi 分别将四个寄存器压栈,压栈的起始位置为(ESP – 1),每次压栈ESP -= 4第二行mov ebp, esp是在完成对原始EBP寄存器的保存后,将调用函数的栈顶设为被调用函数的栈底第三行sub esp, 0D8h即esp -= 0D8h,即将(esp – 0D8h)设为main函数的栈顶在完成对各寄存器状态的保存和函数栈大小的分配后,最后四行汇编源码是对函数栈初始化:lea edi, [ebp – 0D8h]将(ebp – 0F4h) 赋值给EDI寄存器,由于mov操作不支持第二个操作数是一个寄存器减去一个数值,故用lea操作。这里是将栈顶地址赋给EDI寄存器mov ecx, 36h将数值36h赋值给ECX寄存器,0X36 = 0D8h 2,即为main函数栈内存的DWORD数目mov eax, 0CCCCCCCCh将EAX赋值为0CCCCCCCCh,即为INT 3中断rep stos dword ptr es : [edi]rep指令是stos字符串指令的前缀,rep指令使其后的字符串指令被重复直至ECX为0,故ECX即为重复次数,stos指令是一个字符串指令,是将EAX中的值拷贝到ES : EDI指向的地址,再EDI += 4,而dword ptr则是指stos指令一次拷贝双字main函数的函数栈初始化如下图所示:在调用Fun函数时21:Fun (3, 4);001D143Cpush4001D143Epush3001D1440callFun (01D1127h)001D1445addasp, 8Fun函数的调用方式为__cdecl,故实参从右向左压栈,并且__cdecl方式由调用函数清理栈中的实参,add esp, 8为清除实参的指令。call Fun (01D1127h)将跳转到Fun函数的jmp跳转指令地址0x01D1127h处,注意call指令有一个隐含的压栈操作:将函数的返回地址(Fun函数结束后将执行的指令地址,本例中为0x001D1445h)压栈。Fun函数的函数栈初始化

文档评论(0)

haihang2017 + 关注
实名认证
内容提供者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档