x86/x64汇编基础16.汇编基础12:栈操作指令

笔记

学习最新前沿软件逆向安全技术、游戏安全辅助脚本技术,B 站 小迪 xiaodi 老师

微信 i-xiaodi

用于栈的管理。

以下是 x86 32位模式下常见栈操作指令及其功能表:

指令

功能描述

栈指针变化 (ESP)

PUSH

将寄存器值、立即数或内存操作数压入栈顶。例:PUSH EAXPUSH 5

ESP -= 4

POP

栈顶值弹出并存入寄存器或内存操作数。例:POP EAX

ESP += 4

PUSHAD

按顺序将通用寄存器(EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI)的值压入栈。

ESP -= 32

POPAD

按顺序从栈中弹出值恢复到通用寄存器(EDI, ESI, EBP, ESP(跳过), EBX, EDX, ECX, EAX)。

ESP += 32

PUSHFD

将32位标志寄存器(EFLAGS)压入栈。

ESP -= 4

POPFD

从栈中弹出值并恢复到32位标志寄存器(EFLAGS)。

ESP += 4

CALL 地址

调用子程序,将当前指令的返回地址压入栈顶,然后跳转到目标地址。

ESP -= 4

RET

从栈中弹出返回地址并跳转到该地址。

ESP += 4(或更多)

ENTER

设置栈帧:将当前 EBP 压入栈,然后设置新的 EBP 并为局部变量分配空间。

ESP -= 局部变量大小

LEAVE

恢复栈帧:将 EBP 的值恢复到 ESP,然后弹出原 EBP

ESP += 局部变量大小

INT imm8

软中断:将标志寄存器、代码段(CS)和指令指针(EIP)压入栈,然后跳转到中断向量表中的处理程序地址。

ESP -= 12

IRET

中断返回:从栈中弹出标志寄存器、代码段(CS)、指令指针(EIP),恢复中断前状态。

ESP += 12

说明

  1. 栈增长方向:x86 的栈是向下增长的,压栈时 ESP 减小,弹栈时 ESP 增大。
  2. 操作数大小:在32位模式下,栈操作默认是以4字节(32位)为单位。
  3. PUSHADPOPAD
    • 压栈顺序(PUSHAD)
      1. EAX
      2. ECX
      3. EDX
      4. EBX
      5. 当前 ESP 的值(未更新的栈指针)
      6. EBP
      7. ESI
      8. EDI
    • 弹栈顺序(POPAD)
      1. EDI
      2. ESI
      3. EBP
      4. 跳过 ESP(不恢复)
      5. EBX
      6. EDX
      7. ECX
      8. EAX

示例代码

PUSH/POP 示例

PUSH EAX      ; 将 EAX 压入栈,ESP -= 4
PUSH 0x12345678 ; 将立即数 0x12345678 压入栈,ESP -= 4
POP EBX       ; 从栈顶弹出值到 EBX,ESP += 4

函数调用示例

CALL MyFunction  ; 将返回地址压入栈,ESP -= 4
RET              ; 从栈中弹出返回地址并跳转,ESP += 4

栈帧设置示例

ENTER 0x10, 0    ; 设置栈帧,分配16字节的局部变量空间
LEAVE            ; 恢复栈帧

 

拓展

1. LEAVE指令的本质

LEAVE 是 x86 汇编中的一条指令,常用于函数返回之前进行栈帧清理。

功能描述:

LEAVE 的功能相当于以下两条指令:

MOV ESP, EBP
POP EBP

具体操作:

  1. MOV ESP, EBP
    将当前的栈基指针(EBP)的值赋给栈顶指针(ESP),释放局部变量所占的栈空间。
    这一步使 ESP 恢复到进入函数之前的状态。
  2. POP EBP
    从栈中弹出保存的调用者的 EBP 值,恢复调用者的栈基指针。

本质:

LEAVE 是一种简化栈帧清理的指令,目的是恢复函数调用前的栈布局,使得调用者可以正常执行后续代码。


2. ENTER指令的本质

ENTER 是用于设置栈帧的一条复杂指令,功能是为函数调用创建栈帧。

格式:

ENTER imm16, imm8
  • imm16:为栈帧分配的局部变量空间的大小(以字节为单位)。
  • imm8:嵌套层级深度,通常为 0。

功能描述:

ENTER imm16, imm8 相当于以下多条指令:

PUSH EBP            ; 保存当前栈基指针
MOV EBP, ESP        ; 设置新的栈基指针
SUB ESP, imm16      ; 为局部变量分配空间

如果嵌套深度(imm8)为 0,则 ENTER 不会处理更多嵌套逻辑,直接执行上述三步操作。

嵌套层级(imm8)的作用:

当函数有嵌套调用需求时,ENTER 会额外处理保存和管理多级 EBP 指针,用于支持更复杂的栈布局。不过现代编译器通常不会依赖这种功能。

本质:

ENTER 是一种为函数设置栈帧的复合指令,目的是方便管理函数调用过程中的局部变量和嵌套调用栈帧。但由于它的复杂性和效率问题,现代编译器一般直接使用 PUSHMOVSUB 等指令代替。


对比总结

指令

作用

等效操作

常见用途

LEAVE

清理栈帧,恢复调用者状态

MOV ESP, EBP + POP EBP

函数退出前

ENTER

创建栈帧,分配局部变量空间

PUSH EBP + MOV EBP, ESP + 更多

函数入口时(已不常用)

  • 在现代编译器中,ENTERLEAVE 的功能可以被更简单和高效的指令组合替代,因此 ENTER 较少使用,而 LEAVE 仍较为常见。
请登录后发表评论