2.1 堆栈基础
2.1.1 内存区域
-
代码区(Code Segment/Text Segment):通常是指用来存放程序执行代码的一块内 存区域。这个区域存储着被装入执行的二进制机器代码,处理器会到这个区域取指并执行。
-
静态数据区:通常是指用来存放程序运行时的全局变量、静态变量等的内存区域。 通常,静态数据区包括初始化数据区(Data Segment)和未初始化数据区(BSS Segment)两 部分。未初始化数据区BSS区存放的是未初始化的全局变量和静态变量,特点是可读写,在 程序执行之前BSS段会自动清0。
-
堆(Heap)区:用于动态地分配进程内存。进程可以在堆区动态地请求一定大小的 内存,并在用完之后归还给堆区。动态分配和回收是堆区的特点。
-
栈(Stack)区:用于支持进程的执行,动态地存储函数之间的调用关系、局部变量等,以保证被调用函数在返回时恢复到母函数中继续执行。
程序→编译链接→可执行文件(二进制机器代码)
-
在程序运行之前, 代码段和数据段在内存里就确定了。
-
之后,处理器将到内存段区域一条一条地取出指令和操 作数,并送入算术逻辑单元进行运算;
-
如果代码中请求开辟动态内存,则会在==内存的堆区分配==一块大小合适的区域返回给代码区的代码使用;
-
当函数调用发生时,函数的调用关系等信 息会动态地保存在内存的栈区,以供处理器在执行完备调用函数的代码时,返回母函数。
不同操作系统的内存组织形式

2.1.2 堆区和栈区
1. 堆区和栈区
| 对比维度 | 栈(stack) | 堆(heap) |
|---|---|---|
| 存储内容 | 函数运行时的局部变量、数组等 | 程序运行时动态分配的内存 |
| 内存管理 | 系统自动预留和回收,无需程序员参与 | 需程序员使用专有函数(如C语言malloc、C++语言new )申请,释放也需程序员操作(如C语言free 、C++语言delete ) |
| 数据结构特性 | 向低地址扩展,先入后出 | 向高地址扩展 |
| 空间大小限制 | 在WINDOWS下默认大小2M,超出提示溢出 | 受限于计算机虚拟内存 |
| 申请方式 | 系统自动分配,如声明局部变量int b ,系统自动开辟空间 | 程序员自己申请并指明大小,如p1 = (char *)malloc(10) (C语言) |
| 申请效率 | 系统自动分配,速度快,程序员无法控制 | 由程序员分配,速度慢,易产生内存碎片,但使用灵活 |
| 增长方向 | 从高地址向低地址方向增长 | 由低地址向高地址方向增长 |
2. 堆结构
(1)堆块
-
空闲态:链入空链表,由系统管理
-
占有态:占有态的堆块会返回一个由程序员定义的句 柄,通常是一个堆块指针,来完成对堆块内存的读、写和释放操作,由程序员管理。
示意图如下:
-
块首:存放着堆块的信息,空闲堆块,额外存储了4字节的指针:flink指针和blink指针。
-
Flink前向指针存储了前一个空 闲块的地址,Blink后向指针存储了后一个空闲块的地址。
-
指向堆块的指针或者句柄,指向的是块身的首地址。
-
-
块身

(2)堆表
-
占有态堆块被使用它的程序索引
-
堆表只索引空闲态的堆块
两种堆表
-
空闲双向链表 freelist(简称空表)
-
空表索引(空表表头):
-
大小为128的指针数组,该数组的每一项包括两个指针,用于标识一条空表。
-
空表索引的第二项(free[1])标识了堆中所有大小为 8 字节的空闲堆块。
-
之后每个索引项指示的空闲堆块递增8字节。例如,free[2]为16字节的空闲堆块,free[3] 为24字节的空闲堆块,free[127]为1016字节的空闲堆块。
-
把空闲堆块按照大小的不同链入不同的空表,可以方便堆管理系统高效检索指定大小的空闲堆块。
-
空表索引的第一项 free[0]所标识的空表相对比较特殊,这条双向链表链入了所有大于 等于1024字节小于512KB的堆块,升序排列。这个空表通常又称为零号空表。
-
-
空闲链块:
-

-
快速单向链表 lookaside(简称快表)
-
加速堆块分配而采用的堆表,从不发生堆块合并(堆溢出不使用)
-
(3)堆块的分配和释放
堆块分配
依据既定的查找空闲堆块的策略,找到合适的空闲堆块之后,将其状态修改为占用态、把它从堆表中“卸下”、返回一个指向堆块块身的指针给程序使用。
-
首先寻找最优的空闲块分配
-
若失败,稍大的块会被用于分配:从大块中切割出一块进行分配。然后给剩 下的部分重新标注块首,链入空表。也就是说,空表分配存在找零钱的情况。
-
零号空表中按照大小升序链着大小不同的空闲块,故在分配时先从 free[0]反向查找最 后一个块(即最大块),看能否满足要求,如果满足要求,再正向搜索最小能满足要求的空闲 堆块进行分配
堆块释放
堆块的释放操作包括将堆块状态由占用态改为空闲态、链入相应的堆表。所释放的堆块将链入相应链表的表尾。
堆块合并
-
堆块的分配和释放操作可能引发堆块合并,即当堆管理系统发现两个空闲堆 块相邻时,就会进行堆块合并操作。堆块的合并包括几个动作:
-
将堆块从空表中卸下、合并 堆块、修改合并后的块首、链接入新的链表(合并的时候还有一种操作叫内存紧缩)。
2.1.3 函数调用
同一文件不同函数的代码在内存代码区中的分布可能相邻,也可能相离甚远;可能先后有序,也可能无序;可以简单地把它们在内存代码区中的分布位置理解 成是散乱无关的。

函数调用流程如下:
-
参数入栈:将参数从右向左依次压入系统栈中
-
返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈,供函数返回时继续执行
-
代码区跳转:处理器从当前代码区跳转到被调用函数的入口处。
-
栈帧调整:
-
保存当前栈帧状态值,已备后面恢复本栈帧时使用。
-
将当前栈帧状态切换到新栈帧
-
2.1.4 常见寄存器与栈帧
寄存器(register)是中央处理器CPU的组成部分。寄存器是有限存贮容量的高速存贮 部件,它们可用来暂存指令、数据和地址。
-
ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永 远指向系统栈最上面一个栈帧的栈顶。
-
EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针 永远指向系统栈最上面一个栈帧的底部。
-
EIP:指令寄存器(extended instruction pointer),其内存放着一个指针,该指针永远指向下一条等待执行的指令地址。

栈帧中包含以下几类信息
-
局部变量:为函数局部变量开辟的内存空间
-
栈帧状态值:保存前栈帧的顶部和底部(实际上只保存前栈帧的底部,前栈帧的顶 部可以通过堆栈平衡计算得到),用于在本帧被弹出后恢复出上一个栈帧。
-
函数返回地址:保存当前函数调用前的“断点”信息,也就是函数调用前的指令位 置,以便在函数返回时能够恢复到函数被调用前的代码区中继续执行指令。
2.2 汇编语言
-
4 个数据寄存器(EAX、EBX、ECX和EDX) [2]
-
2 个变址寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP) [3]
-
6 个段寄存器(ES、CS、SS、DS、FS和GS) [4]
-
1 个指令指针寄存器(EIP) 1个标志寄存器(EFlags)
2.2.1 主要寄存器
1. 数据寄存器
| 32位 | 16位 | 8位(16位分而成) |
|---|---|---|
| EAX | AX | AH-AL |
| EBX | BX | BH-BL |
| ECX | CX | CH-CL |
| EDX | DX | DH-DL |
-
EAX:累加器,时间较少,乘除、输入/输出等操作,使用频率很高。EAX通常用于存储函数返回值
-
EBX:基地址寄存器:作为存储器指针来使用,访问存储器
-
ECX:计数寄存器:
-
循环中控制循环次数
-
移多位时,使用CL指明移位的位数
-
-
EDX:数据寄存器
-
进行乘除运算的时候,作为默认的操作数参与运算
-
存放I/O的端口地址
-
2. 变址寄存器
主要用来存放操作数的地址,用于堆栈操作和变址运算中计算操作数的有效地址
低16位对应SI,DI
-
ESI:在内存操作指令中作为“源地址指针”,
-
EDI:在内存操作指令中作为“目的地址指针”
3. 指针寄存器
-
EBP:基指针寄存器,通过减去一定的偏移值,来访问栈中的元素
-
ESP:堆栈指针寄存器,始终指向栈顶
4. 段寄存器
段寄存器是根据内存分段的管理模式而设置的。内存单元的物理地址由段寄存器的值和 一个偏移量组合而成的,标准形式为“段:偏移量”,这样可用两个较少位数的值组合成一个 可访问较大物理空间的内存地址。
-
CS——代码段寄存器(Code Segment Register),其值为代码段的段值;
-
DS——数据段寄存器(Data Segment Register),其值为数据段的段值;
-
ES——附加段寄存器(Extra Segment Register),其值为附加数据段的段值;
-
SS——堆栈段寄存器(Stack Segment Register),其值为堆栈段的段值;
-
FS——附加段寄存器(Extra Segment Register),其值为附加数据段的段值;
-
GS——附加段寄存器(Extra Segment Register),其值为附加数据段的段值。
融合变址寄存器,在很多字符串操作指令中,DS:ESI指向源串,而ES:EDI指向目标串。
5. 指令指针寄存器
-
IR:指令寄存器:临时放置从==内存里面取得的程序指令==的寄存器,用于存放当前从主存储器中读出的正在执行的一条指令
-
DR:数据寄存器:执行指令时,从内存中取到数据寄存器,然后再传送至IR。指令划分为操作码和地址码字段。由二进制数字组成
指令指针寄存器(IP):指令指针寄存器存放下次将要执行的指 令在代码段的偏移量。
工作顺序:
-
从IP中获得关于指令的相关内存地址
-
按照正确的方式取出指令
-
将指令放置到原来的指令寄存器中
6. 标志寄存器
EFLAG寄存器
-
Z-Flag(零标志):它可以设成0或者1。
-
O-Flag(溢出标志):反映有符号数加减运算是否溢出。如果运算结果超过了有符号数的表示范围,则OF设置为1,
-
C-Flag(进位标志):反映运算是否产生进位或借位。如果运算结果的最高位产生一个进位或皆为,则CF置为1
2.2.2 寻址方式
1. 指针寻址
-
顺序寻址方式:一条指令接着指令执行
需要使用指令计数器来完成顺序指令寻址。指令计数器是计算机处理器中的一个 包含当前正在执行指令地址的寄存器,
-
X86中称为指令指针IP寄存器
-
ARM或C51:程序计数器(PC)。
每执行完一条指令时,指令计数器中的地址或自动加1或转移指针给出下一条指令的地址
-
-
跳跃寻址方式:当程序专业执行的顺序时,指令的寻址就采取跳跃寻址方式。
-
跳跃:下条指令的地址码不由程序计数器给出,而是由本条指令给出。程序跳转后,按新的指令地址开始顺序执行。(程序计数器的内容也必须做出改变)
-
采用指令跳跃寻址方式,可以实现程序转移或构成循环程序,
-
2. 操作数寻址
-
立即寻址
-
指令的地址字段指出的不是操作数的地址,而是操作数本身,这种寻址方式称为立即寻址。
-
特点:执行时间很短,不需要访问内存取数,节省了内存访问的时间
MOV CL, 05H -
-
直接寻址
在指令中直接给出操作数的有效地址。
MOV AL,[3100H]MOV AL, ES:[3100H] -
间接寻址:在间接寻址的情况下,指令地址字段中的 形式地址不是操作数的真正地址,而是操作数地址的指示器
MOV [BX], 12H -
相对寻址:操作数有效地址 = 基址寄存器/变址寄存器 + 指令中给定的偏移量
MOV AX, [DI + 1234H] -
基址变址寻址:基址寄存器+变址寄存器=有效地址
-
MOV EAX, [BX+SI] -
MOV EAX, [BX][SI] -
MOV EAX, [SI][BX]
-
-
相对基址变址:
-
MOV EAX, [EBX+ESI+1000H] -
MOV EAX, 1000H [BX][SI]
-
2.2.3 主要指令
1. 数据传输指令集
-
MOV: 把源操作数送给目的操作数
-
XCHG: 交换两个操作数的数据
-
PUSH,POP: 把操作数压入或取出堆栈
-
PUSHF,POPF,PUSHA,POPA: 堆栈指令群
-
LEA,LDS,LES: 取地址至寄存器
2. 算数运算指令
-
ADD, ADC:加法指令
-
SUB,SBB:减法指令
-
INC, DEC: 把 OP 的值加一或减一
-
NEG: 将 OP 的符号反相(取二进制补码)
-
MUL,IMUL: 乘法指令
-
DIV,IDIV:除法指令
3. 位运算指令集
-
AND,OR,XOR,NOT,TEST: 执行 BIT 与 BIT 之间的逻辑运算
-
SHR,SHL,SAR,SAL: 移位指令
-
ROR,ROL,RCR,RCL: 循环移位指令
举例: AND (逻辑与)语法: AND 目标数, 源数
AND 运算对两个数进行逻辑与运算(当且仅当两操作数对应位都为“1”时结果的相应位 为“1”,否则结果相应位为“0”),目标数=目标数 AND 源数。 AND 指令会清空OF、CF标记,设置ZF标记。
4. 程序流程控制指令集
-
CLC,STC,CMC: 设定进位标志
-
CLD,STD: 设定方向标志
-
CLI,STI: 设定中断标志
-
CMP: 比较OP1 与OP2的值
-
JMP: 跳往指定地址执行
-
LOOP: 循环指令集
-
CALL,RET: 子程序调用,返回指令
-
INT,IRET: 中断调用及返回指令。在执行 INT 时,CPU 会自动将标志寄存器的值入栈,在 执行IRET时则会将堆栈中的标志值弹回寄存器
-
REP, REPE, REPNE: 重复前缀指令集
5. 条件转移命令
-
JXX: 当特定条件成立则跳往指定地址执行
常用:
Z:为0转移
G:大于则转移
L:小于则转移
E:等于则转移
N:取相反条件
6. 字符串操作指令集
-
MOVSB,MOVSW,MOVSD: 字符串传送指令
-
CMPSB,CMPSW,CMPSD: 字符串比较指令
-
SCASB,SCASW: 字符串搜索指令
-
LODSB,LODSW,STOSB,STOSW: 字符串载入或存贮指令
### 参考文献
[1] 刘哲理, 贾岩, 范玲玲, 等. 软件安全:漏洞利用及渗透测试[M]. 北京:清华大学出版社,2022.
5900

被折叠的 条评论
为什么被折叠?



