堆栈基础(一)

新手入门pwn之栈溢出系列,先学习堆栈的基础,函数调用栈这些.

运行时栈

运行时栈(runtime stack)是有cpu内部硬件直接支持的, 也是实现过程调用和过程返回机制的基本组成部分。 在大多数时我们称运行时栈为: 堆栈

这里的堆栈和数据结构里的栈抽象数据类型是不同的,堆栈即运行时栈在系统层上(由硬件直接实现) 处理子过程调用; 堆栈抽象数据类型通常用于实现依赖后进先出操作的算法,一般使用高级语言如c++/java等编写。

栈方向

https://www.zhihu.com/question/36103513
https://www.cnblogs.com/xkfz007/archive/2012/06/22/2558935.html

栈方向跟体系结构有关系,x86是向下增长,x86硬件直接支持的栈确实是“向下增长”的,由高地址向低地址增长:push指令导致sp自减一个slot,pop指令导致sp自增一个slot。其它硬件有其它硬件的情况。arm没有固定,但一般操作系统会选择向下增长

image.png

在内存管理中,与栈对应是堆。对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方式是向下的,是向着内存地址减小的方向增长。在内存中,“堆”和“栈”共用全部的自由空间,只不过各自的起始地址和增长方向不同,它们之间并没有一个固定的界限,如果在运行时,“堆”和 “栈”增长到发生了相互覆盖时,称为“栈堆冲突”,系统肯定垮台。

三个寄存器

函数状态主要涉及三个寄存器

rsp/esp/sp:栈指针寄存器,其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶

rbp/ebp/bp:基址指针寄存器,其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部函数栈帧

rip/eip/ip:指令寄存器, 其内存放着一个指针,该指针永远指向下一条待执行的指令地址。
image.png

push / pop操作

运行时栈是有cpu直接管理的内存数组, 它使用连个寄存器,ss和esp(32是esp,16位是sp,64位是rsp), ss寄存器存放的段地址,esp是堆栈指针寄存器,指向最后压入到堆栈上的数据。我们很少直接操纵esp的值,而是由call,ret,push和pop指令间接修改的。

堆栈段的操作步骤

压栈(入栈)push sth-> [esp]=sth,esp=esp-4
弹栈(出栈)pop sth-> sth=[esp],esp=esp+4

http://bestwing.me/2017/03/18/stack-overflow-one/

函数调用方式和栈帧

参考:https://www.zhihu.com/question/22444939

如下代码:

#include<stdio.h>

void func_A(int arg_A1, int arg_A2);
void func_B(int arg_B1, int arg_B2,int arg_B3);
int main(int argc, char *argv[], char **envp){
    printf("main start");
    int arg_A1 = 1;
    int arg_A2 = 2;
    func_A(arg_A1, arg_A2);
}
void func_A(int arg_A1, int arg_A2){
    int arg_A3 = 3;
    func_B(arg_A1,arg_A2,arg_A3);
}
void func_B(int arg_B1, int arg_B2,int arg_B3){
    printf("%d,%d,%d\n",arg_B1,arg_B2,arg_B3);
}


函数调用大致包括以下几个步骤:

参数入栈:将参数从右向左依次压入系统栈中
返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继续执行
代码区跳转:处理器从当前代码区跳转到被调用函数的入口处
栈帧调整:
    具体包括保存当前栈帧状态值,已备后面恢复本栈帧时使用(EBP入栈)
    将当前栈帧切换到新栈帧。(将ESP值装入EBP,更新栈帧底部)
    局部变量入栈,esp减小

恢复的过程就是现弹出栈帧(pop ebp),这样就可以恢复出调用函数的栈帧了,此时栈顶会指向返回地址,再将返回地址弹出(pop eip),并保存到eip中,之后就会回到原来调用函数的下一条地址继续运行了。

栈帧的调整过程:

在main函数调用func_A的时候,首先在自己的栈帧中压入函数返回地址,

然后为func_A创建新栈帧并压入系统栈,在func_A调用func_B的时候,同样先在自己的栈帧中压入函数返回地址,

然后为func_B创建新栈帧并压入系统栈, 在func_B返回时,func_B的栈帧被弹出系统栈,func_A栈帧中的返回地址被“露”在栈顶,此时处理器按照这个返回地址重新跳到func_A代码区中执行在func_A返回时,func_A的栈帧被弹出系统栈,main函数栈帧中的返回地址被“露”在栈顶,此时处理器按照这个返回地址跳到main函数代码区中执行在实际运行中,

main函数并不是第一个被调用的函数,程序被装入内存前还有一些其他操作,上图只是栈在函数调用过程中所起作用的示意图

函数调用图如下:

image.png

栈帧调整图如下:

image.png

函数调用时栈内的数据从高地址到低地址分别是函数参数入栈(从右到左),返回地址入栈,ebp入栈,esp分配填充地址, 局部变量mov入栈.

函数调用的汇编代码为:

main函数

push ebp    //保留旧栈帧
mov ebp,esp //分配新的栈帧               
sub esp,4C  //设置填充空间大小为4C                   
push ebx //寄存器入栈
push esi                       
push edi                         
lea edi,dword ptr ss:[ebp-4C] 将栈顶指针地址给edi   
mov ecx,13  //计数器设置为13                     
mov eax,CCCCCCCC //填充数据            
rep stosd dword ptr es:[edi],eax //重复填充13次0xccccccc到[ebp-4C]~[ebp]到这个空间
mov dword ptr ss:[ebp-4],pwn3.42201C  //pwn3.c:6, [ebp-4]:"test programmer", 42201C:"test programmer" //局部变量入栈(并不是push的)
mov dword ptr ss:[ebp-8],1   //pwn3.c:7 局部变量入栈
mov dword ptr ss:[ebp-C],2    //pwn3.c:8 局部变量入栈
mov eax,dword ptr ss:[ebp-C]  //pwn3.c:9
push eax   //右边第一个参数2入栈                      
mov ecx,dword ptr ss:[ebp-8]     
push ecx  //右边第二个参数1入栈                       
call <pwn3.ILT+5(_func_A)>  //函数调用   

参数入栈的方式:取决于调用约定,一般情况下:
X86 从右向左入栈,X64 优先寄存器,参数过多时才入栈

image.png

main函数的栈帧:

ebp:0019ff40

我们看到函数调用后首先是函数参数入栈,函数调用后会发生什么呢? 我们来看一看

push ebp 保存main函数的栈帧ebp
mov ebp,esp  //设置funcA的栈帧ebp                    
sub esp,44  //给fucA栈帧分配填充字节空间44                     
push ebx //寄存器入栈                        
push esi                         
push edi                         
lea edi,dword ptr ss:[ebp-44]    
mov ecx,11                       
mov eax,CCCCCCCC                 
rep stosd dword ptr es:[edi],eax //填充同上
mov dword ptr ss:[ebp-4],3 //局部变量mov入栈
mov eax,dword ptr ss:[ebp-4] 
push eax //函数参数push入栈                        
mov ecx,dword ptr ss:[ebp+C]     
push ecx                         
mov edx,dword ptr ss:[ebp+8]     
push edx                          edx:&"ALLUSERSPROFILE=C:\\ProgramData"
call <pwn3.ILT+10(_func_B)>  //调用fucB    
add esp,C                        
pop edi                           pwn3.c:14
pop esi                          
pop ebx                          
add esp,44                       
cmp ebp,esp                      
call <pwn3._chkesp>              
mov esp,ebp                      
pop ebp                          
ret                              
image.png

func_A的栈帧: ebp=0019FED8

func_B的汇编代码:

push ebp  
mov ebp,esp   
sub esp,40 
push ebx  
push esi  
push edi     
lea edi,dword ptr ss:[ebp-40] 
mov ecx,10 
mov eax,CCCCCCCC   
rep stosd dword ptr es:[edi],eax  
mov eax,dword ptr ss:[ebp+10]
push eax   //函数参数入栈  
mov ecx,dword ptr ss:[ebp+C] 
push ecx    
mov edx,dword ptr ss:[ebp+8]
push edx    
push pwn3.422030  
422030:"%d,%d,%d\n"
call <pwn3.printf> 
add esp,10   
pop edi  
pop esi  
pop ebx
add esp,40 
cmp ebp,esp  
call <pwn3._chkesp>  
mov esp,ebp  
ret 

将这段代码的所有汇编一步一步跟踪了解清楚了后,对堆栈算是大概了解了,下面就是入门栈溢出了,之后学到栈溢出再来更新.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容