X86汇编PUSH与POP操作对于变量在内存中高低地址的转换分析

一、高低地址的核心概念

内存可以看作是一段线性的、按字节编号的存储空间,就像一条无限长的街道,每个字节都是一个"房子",每个房子有唯一的"门牌号"(地址):

  • 低地址 :地址数值的内存位置(比如 0x00001000)。
  • 高地址 :地址数值的内存位置(比如 0x00002000)。

举个通俗例子:把内存地址想象成楼层号,低地址是1楼、2楼(数值小),高地址是10楼、20楼(数值大)。

关键特性(x86架构,逆向最常用):

栈的生长方向是从高地址向低地址扩展 ------压栈(push)数据时,栈顶寄存器esp的数值会减小 (指向更低的地址);出栈(pop)数据时,esp数值会增大(指向更高的地址)。

二、结合栈帧的具体地址数值举例

以32位x86系统(逆向最经典场景)为例,用main函数调用add(a=1, b=2)的过程,一步步展示栈地址的变化,所有地址均为十六进制(逆向标准表示)。

前提约定:
  • 32位系统中,每个栈操作(push/pop)占用4字节(地址增减步长为4)。
  • 调用约定为cdecl(C语言默认):参数从右到左入栈,返回地址由call指令保存。
  • 初始状态:main函数的栈帧基址ebp=0x0012FF80(栈帧底部,高地址),esp=0x0012FF80(栈顶,初始与底部重合)。
步骤1:参数入栈(main调用add前)

cdecl约定下,参数从右到左压栈(先压b,再压a):

  1. 压入参数b=2:
    • 执行push 2esp = 0x0012FF80 - 4 = 0x0012FF7C(地址减小,指向更低地址)。
    • 内存地址0x0012FF7C(高地址)存储数值2。
  2. 压入参数a=1:
    • 执行push 1esp = 0x0012FF7C - 4 = 0x0012FF78
    • 内存地址0x0012FF78(低地址)存储数值1。

此时栈地址分布(高→低):

地址(十六进制) 存储内容 说明
0x0012FF7C 2(参数b) 高地址
0x0012FF78 1(参数a) 低地址(栈顶当前)
步骤2:保存返回地址(call指令)

执行call add时,CPU会先把main函数下一条指令的地址(返回地址,假设为0x00401020)压入栈,再跳转到add函数:

  • esp = 0x0012FF78 - 4 = 0x0012FF74
  • 内存地址0x0012FF74存储返回地址0x00401020
步骤3:建立add函数的栈帧

进入add函数后,首先执行栈帧初始化指令:

  1. 保存旧ebp(main的ebp):
    • 执行push ebpesp = 0x0012FF74 - 4 = 0x0012FF70
    • 内存地址0x0012FF70存储0x0012FF80(main的ebp值)。
  2. 设置新ebp(add的栈帧底部):
    • 执行mov ebp, esp,此时ebp = 0x0012FF70(add栈帧的底部,高地址)。
  3. 分配局部变量(比如add的局部变量c):
    • 执行sub esp, 4(分配4字节),esp = 0x0012FF70 - 4 = 0x0012FF6C(add栈帧的顶部,低地址)。
    • 内存地址0x0012FF6C存储局部变量c(初始值随机,比如0)。
最终add栈帧的完整地址分布(高→低)
地址(十六进制) 存储内容 角色 地址属性
0x0012FF70 0x0012FF80(main的ebp) add栈帧底部(ebp) 高地址
0x0012FF74 0x00401020(返回地址) 返回地址 -
0x0012FF78 1(参数a) 函数参数 -
0x0012FF7C 2(参数b) 函数参数 -
0x0012FF6C 0(局部变量c) add栈帧顶部(esp) 低地址

三、补充说明

  1. 上述地址是示例值 ,实际系统中地址会因操作系统(Windows/Linux)、编译器(MSVC/GCC)、ASLR(地址随机化)等因素变化,但高低地址的相对关系永远不变
  2. 64位系统的栈操作逻辑与32位一致,仅地址宽度变为64位(比如0x000000000012FF80),每次push/pop的步长为8字节。
  3. ebp(栈帧基址)的核心作用是"锚定"栈帧:通过ebp+偏移量可以精准访问参数(如ebp+8是参数a)、局部变量(如ebp-4是局部变量c),这是逆向中定位参数/变量的关键。

总结

  1. 内存地址数值越大,地址越高;数值越小,地址越低,栈在x86架构下从高地址向低地址生长。
  2. 栈帧中ebp指向栈帧底部(高地址),esp指向栈帧顶部(低地址),push操作使esp减小,pop使esp增大。
  3. 函数调用时,栈地址从高到低依次存储:旧ebp → 返回地址 → 函数参数 → 局部变量。
相关推荐
188号安全攻城狮3 天前
【请假,后面补】WinDbg 核心调试操作
汇编·安全·网络安全
万法若空6 天前
8086/8088实模式的内存布局
汇编
浩浩测试一下7 天前
内网---> WriteOwner权限滥用
网络·汇编·windows·安全·microsoft·系统安全
一品人家7 天前
win32汇编使用GDI+入门教程之九
汇编·windows·win32汇编
虚构之人8 天前
二进制漏洞挖掘(WinAFL Fuzzing)Windows篇
汇编·网络安全·信息安全·系统安全
一品人家10 天前
win32汇编使用GDI+入门教程之六
汇编·windows·win32汇编
前端菜鸟日常11 天前
鸿蒙开发实战:100 个项目疑难杂症汇编
汇编·华为·harmonyos
188号安全攻城狮12 天前
【PWN】HappyNewYearCTF_9_ret2syscall
linux·汇编·安全·网络安全·系统安全
万法若空12 天前
Vim常用指令汇编
汇编·编辑器·vim