常见寄存器
32位:
4个数据(通用)寄存器:(eax、ebx、ecx、edx) 6个段寄存器:(ES、CS、SS、DS、FS、GS) 2个变址寄存器:(ESI、EDI) 2个指针寄存器(ESP、EBP) 1个指令指针寄存器:EIP
32位CPU有4个32位通用寄存器:eax、ebx、ecx、edx。
段寄存器
段寄存器:在8086系统中,访问存储器的地址码由段地址和段内偏移地址两部分组成。段寄存器用来存放各分段的逻辑基值,并指示当前正在使用的4个逻辑段,包括代码段寄存器CS、堆栈段寄存器SS、数据段寄存器DS和附加段数据寄存器ES。
32位CPU有6个段寄存器,分别如下:
CS:代码段寄存器 ES:附加段寄存器
DS:数据段寄存器 FS:附加段寄存器
SS:堆栈段寄存器 GS:附加段寄存器
在16位CPU系统中,只有4个段寄存器(CS、DS、ES、SS)
变址寄存器
32位CPU有2个32位通用寄存器ESI和EDI,其低16位对应8086CPU中的SI和DI,对低16位数据的存取,不影响高16位的数据。
esi、edi、si和di称为变址寄存器,它们主要用于存放存储单元在段内的偏移量,用它们可实现多种存储器。
指针寄存器
32位CPU有2个32位通用寄存器EBP和ESP,其低16位对应先前CPU中的BP和SP,对低16位数据的存取,不影响高16位的数据。
EBP、ESP、BP和SP称为指针寄存器,主要用于存放堆栈内存储单元的偏移量,用它们可实现多种存储器。
ebp为基指针寄存器,用它可直接存取堆栈中的数据。
esp为堆栈指针寄存器,用它只可访问栈顶。
指令指针寄存器
32位CPU把指令指针扩展到32位,并记作EIP,EIP的低16位与先前CPU中的IP作用相同。
指令指针EIP、IP是存放下次将要执行的指令在代码段的偏移地址。
64位:
X86-64有16个64位寄存器,分别是:%rax,%rbx,%rcx,%rdx,%esi,%edi,%rbp,%rsp,%r8,%r9,%r10,%r11,%r12,%r13,%r14,%r15。
%rax 作为函数返回值使用。
%rsp 栈指针寄存器,指向栈顶
%rdi,%rsi,%rdx,%rcx,%r8,%r9 用作函数参数,依次对应第1参数,第2参数
%rbx,%rbp,%r12,%r13,%r14,%r15 用作数据存储,调用子函数之前要备份它,以防被修改
%r10,%r11 数据存储,使用之前要先保存原值
寄存器%eax、%edx和%ecx为主调函数保存寄存器(caller-saved registers),当函数调用时,若主调函数希望保持这些寄存器的值,则必须在调用前显式地将其保存在栈中;被调函数可以覆盖这些寄存器,而不会破坏主调函数所需的数据。寄存器%ebx、%esi和%edi为被调函数保存寄存器(callee-saved registers),即被调函数在覆盖这些寄存器的值时,必须先将寄存器原值压入栈中保存起来,并在函数返回前从栈中恢复其原值,因为主调函数可能也在使用这些寄存器。此外,被调函数必须保持寄存器%ebp和%esp,并在函数返回后将其恢复到调用前的值,即必须恢复主调函数的栈帧。
汇编指令
mov
mov %esp,%ebp
将主调函数的栈顶指针%esp赋给被调函数帧基指针%ebp。此时,%ebp指向被调函数新栈帧的起始地址(栈底),亦即旧%ebp入栈后的栈顶
push & pop
相关寄存器: esp, ebp
相关操作: pop, push
//建立被调用者函数的堆栈框架
push %ebp
mov %esp, %ebp
//拆除框架
mov %ebp, %esp
pop %ebp
ret
push:压栈
push %eax
栈顶指针ESP减小4个字节;以字节为单位将寄存器数据(四字节,不足补零)压入堆栈,从高到低按字节依次将数据存入ESP-1、ESP-2、ESP-3、ESP-4指向的地址单元
相当于:
sub $4, %esp//栈顶指针减4
mov %eax, %esp//%eax -> esp 地址
pop:出栈
pop %eax
栈顶指针ESP指向的栈中数据被取回到寄存器;栈顶指针ESP增加4个字节
mov (%esp), %eax
add %4, %esp//栈顶指针加4
call&ret
call 0x111
将当前的指令指针EIP(该指针指向紧接在call指令后的下条指令)压入堆栈,以备返回时能恢复执行下条指令;然后设置EIP指向被调函数代码开始处,以跳转到被调函数的入口地址执行
push %eip
mov $0x111, %eip//当前地址压栈,存入新地址
ret
与call指令配合,用于从函数或过程返回。从栈顶弹出返回地址(之前call指令保存的下条指令地址)到EIP寄存器中,程序转到该地址处继续执行(此时ESP指向进入函数时的第一个参数)。使用该指令前,应使当前栈顶指针所指向位置的内容正好是先前call指令保存的返回地址。
pop %eip
enter&leave
enter
push %ebp
mov %esp, %ebp//将堆栈置空(栈上重堆)
leave
恢复主调函数的栈帧以准备返回。等价于指令序列movl %ebp, %esp(恢复原ESP值,指向被调函数栈帧开始处)和popl %ebp(恢复原ebp的值,即主调函数帧基指针)
mov %ebp, %esp
pop %ebp//将堆栈置空(撤销堆栈)
sub
sub %esp
将栈顶指针%esp减去指定字节数(栈顶下移),即为被调函数局部变量开辟栈空间。为立即数且通常为16的整数倍(可能大于局部变量字节总数而稍显浪费,但gcc采用该规则保证数据的严格对齐以有效运用各种优化编译技术)
栈介绍
栈是一种典型的先进后出( First in Last Out )的数据结构,其操作主要有压栈(push)与出栈(pop)两种操作,如下图所示。两种操作都操作栈顶,当然,它也有栈底。
每个程序在运行时都有虚拟地址空间,其中某一部分就是该程序对应的栈,用于保存函数调用信息和局部变量。此外,常见的操作也是压栈与出栈。
函数调用栈
程序的执行过程可看作连续的函数调用。当一个函数执行完毕时,程序要回到调用指令的下一条指令(紧接call指令)处继续执行。函数调用过程通常使用堆栈实现,每个用户态进程对应一个调用栈结构(call stack)。编译器使用堆栈传递函数参数、保存返回地址、临时保存寄存器原有值(即函数调用的上下文)以备恢复以及存储本地局部变量。
栈增长方向:高地址->低地址
调用方式 | cdecl | stdcall | fastcall |
---|---|---|---|
参数传递 | 从右到左压栈 | 从右到左压栈 | 左边两个参数 分别放在ECX 和EDX寄存器, 其余的参数从 右到左压栈 |
栈清理 | 调用者 | 函数自身 | 函数自身 |
栈帧
函数调用经常是嵌套的,堆栈中会有多个函数的信息。每个未完成运行的函数均占用一个独立的连续区域,称作栈帧。栈帧是堆栈的逻辑片段,当调用函数时栈帧被压入堆栈, 当函数返回时栈帧被从堆栈中弹出。
栈帧存放着函数参数,局部变量及恢复前一栈帧所需要的数据等。编译器利用栈帧,使得我们可以清楚函数参数和函数中局部变量的分配与释放。编译器将控制权移交函数本身之前,插入特定代码将函数参数压入栈帧中,并分配足够的内存空间用于存放函数中的局部变量。
栈帧对函数的每次递归调用,都会分配给该函数一个新的栈帧,这样就巧妙地隔离当前调用与上次调用。栈帧的边界由栈帧基地址指针EBP和堆栈指针ESP界定。EBP指向当前栈帧底部(高地址),在当前栈帧内位置固定;ESP指向当前栈帧顶部(低地址),当程序执行时ESP会随着数据的入栈和出栈而移动。因此函数中对大部分数据的访问都基于EBP进行。
函数调用
在调用一个函数时,系统会为这个函数分配一个栈帧,栈帧空间为该函数所独有。
调用者调用一个函数的过程大致如下:
函数参数从右到左入栈,返回地址入栈,上一函数ebp入栈
在上一函数ebp入栈后,就开辟了被调函数的新栈帧,接下来便是被调函数临时变量入栈等操作,如果被调函数里有继续调用新函数的操作,将继续开始上述的一系列操作,不断循环嵌套下去。下图表示函数调用过程中栈的布局情况。
函数调用结束时的变化,主要就是按相反的顺序将数据弹出栈:
弹出临时变量,弹出调用函数的ebp值,存到ebp寄存器中,弹出返回地址,存到eip寄存器中
返回地址是用call指令调用函数时下一条指令的地址,存到eip中,程序继续执行下一条指令。
函数调用约定
创建一个栈帧的最重要步骤是主调函数如何向栈中传递函数参数。主调函数必须精确存储这些参数,以便被调函数能够访问到它们。函数通过选择特定的调用约定,来表明其希望以特定方式接收参数。此外,当被调函数完成任务后,调用约定规定先前入栈的参数由主调函数还是被调函数负责清除,以保证程序的栈顶指针完整性。
函数参数的传递顺序和方式:
最常见的参数传递方式是通过堆栈传递。主调函数将参数压入栈中,被调函数以相对于帧基指针的正偏移量来访问栈中的参数。对于有多个参数的函数,调用约定需规定主调函数将参数压栈的顺序(从左至右还是从右至左)。某些调用约定允许使用寄存器传参以提高性能。
栈的维护方式:
主调函数将参数压栈后调用被调函数体,返回时需将被压栈的参数全部弹出,以便将栈恢复到调用前的状态。该清栈过程可由主调函数负责完成,也可由被调函数负责完成。
Name-mangling策略:
又称函数名修饰(Decorated Name)规则。编译器在链接时为区分不同函数,对函数名作不同修饰。若函数之间的调用约定不匹配,可能会产生堆栈异常或链接错误等问题。因此,为了保证程序能正确执行,所有的函数调用均遵守一致的调用约定。
一个想入门pwn的垃圾ctfer,哪里不对或理解错误还请大佬们指点。
这篇文章也在本地积累了一段时间,某些内容具体来源也记不清了,还请大佬们海涵
来源:freebuf.com 2021-03-07 20:56:30 by: D1stiny
请登录后发表评论
注册