x86 汇编语言 中,“PUSH” 指令溢出(Stack Overflow)

B站影视 日本电影 2025-09-03 17:42 1

摘要:在 x86 汇编语言 中,"PUSH" 指令溢出(Stack Overflow) 是指 栈空间耗尽,导致无法继续压入数据。这通常是由于 递归调用过深 或 栈空间分配不足 引起的。以下是几种典型的 "PUSH" 溢出场景及示例:

在 x86 汇编语言 中,"PUSH" 指令溢出(Stack Overflow) 是指 栈空间耗尽,导致无法继续压入数据。这通常是由于 递归调用过深 或 栈空间分配不足 引起的。以下是几种典型的 "PUSH" 溢出场景及示例:

***

1. 递归调用过深(无限递归)

问题描述

- 函数 无限递归调用自身,每次调用都会 "PUSH" 返回地址和局部变量,最终耗尽栈空间。

- 栈溢出错误:"Stack Overflow"(程序崩溃)。

示例代码(32位模式)

section .text

global _start

_start:

call recursive_func ; 调用递归函数

mov eax, 1 ; 退出程序

int 0x80

recursive_func:

push eax ; 保存寄存器(模拟局部变量)

call recursive_func ; 无限递归!

pop eax ; 永远不会执行到这里

ret

运行结果

- 每次 "call recursive_func" 会:

1. "PUSH" 返回地址(4字节)。

2. "PUSH EAX"(4字节)。

- 栈指针 "ESP" 不断减小,直到 超出栈空间边界,触发 "Stack Overflow"。

***

2. 栈空间分配不足

问题描述

- 程序 未分配足够栈空间,但频繁 "PUSH" 数据。

- 常见于 嵌入式系统 或 内核开发(栈大小受限)。

示例代码(16位实模式)

org 100h

start:

mov sp, 0x100 ; 手动设置栈指针(SP=0x100,栈空间仅256字节)

mov cx, 100 ; 循环100次

loop_start:

push ax ; 每次循环 PUSH AX(2字节)

dec cx

jnz loop_start

mov ah, 4Ch ; 退出程序

int 21h

运行结果

- 每次 "PUSH AX" 会减少 "SP" 2字节。

- 循环 100 次后,"SP" 从 "0x100" 减少到 "0x100 - 200 = 0x38"。

- 如果栈空间不足(如 "SP

***

3. 中断嵌套过深

问题描述

- 中断处理函数 中再次触发中断(嵌套中断),每次中断都会 "PUSH" 标志寄存器、返回地址等。

- 如果中断频率过高,栈会迅速耗尽。

示例场景

; 假设中断处理函数(IRQ0 时钟中断)

irq0_handler:

pushad ; 保存所有通用寄存器(32字节)

pushfd ; 保存标志寄存器(4字节)

; ...(处理中断)

call nested_irq ; 嵌套调用其他中断

popfd

popad

iret

nested_irq:

pushad

pushfd

; ...(嵌套中断逻辑)

popfd

popad

ret

运行结果

- 每次中断会 "PUSH" 至少 36 字节("PUSHAD" + "PUSHF")。

- 如果中断嵌套 10 次,栈将消耗 "36 * 10 = 360 字节"。

- 默认栈空间可能不足(如 DOS 下栈仅 1KB),导致溢出。

***

4. 缓冲区溢出攻击(恶意 PUSH)

问题描述

- 攻击者通过 缓冲区溢出 覆盖返回地址,并注入恶意代码。

- 恶意代码可能包含 大量 "PUSH" 指令,故意耗尽栈空间。

示例攻击

; 恶意代码片段

malicious_code:

push eax ; 填充栈

push ebx

; ...(重复数千次)

jmp exploit ; 跳转到攻击代码

运行结果

- 恶意 "PUSH" 指令会快速耗尽栈空间,导致程序崩溃或执行攻击代码。

***

如何避免 "PUSH" 溢出?

1. 控制递归深度:

- 确保递归函数有 终止条件。

recursive_func:

cmp ecx, 0 ; 终止条件

je exit

dec ecx

push eax

call recursive_func

pop eax

exit:

ret

2. 增加栈空间:

- 在 链接器脚本 或 程序初始化 时分配更大栈空间。

; Linux 32位程序示例

section .stack

resb 8192 ; 分配 8KB 栈空间

3. 避免中断嵌套:

- 在中断处理中 禁用中断("CLI"),防止嵌套。

irq_handler:

cli ; 禁用中断

pushad

; ...(处理中断)

popad

sti ; 启用中断

iret

4. 检查栈指针:

- 在关键代码前检查 "ESP" 是否接近栈底。

check_stack:

mov eax, [stack_bottom]

sub eax, esp ; 计算剩余栈空间

cmp eax, 1024 ; 至少保留 1KB

jb stack_overflow

ret

stack_overflow:

; 处理栈溢出

***

总结

| 场景 | 原因 | 后果 |

||||

| 无限递归 | 递归无终止条件,"PUSH" 过多 | "Stack Overflow" 崩溃 |

| 栈空间不足 | 手动分配栈太小,"PUSH" 超出范围 | 内存覆盖,程序异常 |

| 中断嵌套 | 中断处理中再次触发中断 | 栈快速耗尽 |

| 缓冲区溢出攻击 | 恶意代码故意 "PUSH" 耗尽栈 | 程序崩溃或执行恶意代码 |

关键点:"PUSH" 溢出本质是 栈空间耗尽,需通过合理设计算法、分配足够栈空间和防御性编程来避免。

来源:动人教育

相关推荐