当前位置: 首页 > news >正文

C/C++反汇编之函数栈帧的理解

🎯 二进制安全必备:函数栈帧与反汇编全景复习笔记

这份笔记为你完整还原了 C 语言源码到经典 x86(32位 Intel 语法、无优化编译)反汇编的映射关系,包含了行级详细解析与核心复习表。你可以直接复制本段 Markdown 源码保存为本地文件,方便随时复盘。


💻 1. C 语言源代码

intmain(){add(0xAA,0xBB);return0;}voidadd(intx,inty){intz=0xCC;}

🛠️ 2. 反汇编代码行级详解

🏢 main 函数反汇编流

; ======= main 函数的开端 (函数序言 Prologue) ======= push ebp ; 1. 将 main 上级函数的 EBP 压栈备份(保存现场) mov ebp, esp ; 2. 让 EBP 等于当前的 ESP,正式确立 main 函数自己的栈帧基准线 ; ======= 准备参数并调用 add(0xAA, 0xBB) ======= push 0BBh ; 3. [对应C: y = 0xBB] 将第二个参数压入栈顶 (ESP = ESP - 4) push 0AAh ; 4. [对应C: x = 0xAA] 将第一个参数压入栈顶 (ESP = ESP - 4) ; 注:x86 下参数按从右往左(Right-to-Left)顺序压栈 call _add ; 5. [对应C: add(...)] 核心动作: ; A. 将下一行指令的地址(返回地址)压入栈顶 (ESP = ESP - 4) ; B. 将 EIP 寄存器修改为 _add 函数的入口地址,实现跳转 ; ======= 从 add 函数返回后的清理工作 ======= add esp, 8 ; 6. [栈平衡 Balance] 重点!由调用者(main)亲自清理栈顶。 ; 刚才 push 了两个参数(4字节 + 4字节 = 8字节), ; 这里把 ESP 加上 8,强行把这两个参数从栈顶“踢除” ; ======= main 函数的收尾 (函数尾声 Epilogue) ======= xor eax, eax ; 7. [对应C: return 0] 清零 EAX,作为 main 函数的默认返回值 pop ebp ; 8. 弹栈,恢复 main 上级函数的 EBP ret ; 9. 结束 main 函数,返回更上层

🧪 add 函数反汇编流

_add proc near ; add 函数入口 ; ======= 1. 函数序言 (建立专属办公室) ======= push ebp ; 将 main 函数的 EBP 压栈备份 (ESP = ESP - 4) mov ebp, esp ; 让 EBP 等于当前的 ESP。从此,当前函数的 EBP 固定在分水岭位置! ; ======= 2. 局部变量空间开辟 ======= sub esp, 4 ; [对应C: int z] 将 ESP 减去 4,在栈上强行留出 4 字节的空地给变量 z ; ======= 3. 执行业务逻辑 (赋值) ======= mov dword ptr [ebp-4], 0CCh ; [对应C: z = 0xCC] ; 往 [EBP - 4](刚才开辟的空地)写入 4 字节的常数 0xCC ; ======= 4. 函数尾声 (拆除办公室、退租) ======= mov esp, ebp ; 清空局部变量!让 ESP 直接回到 EBP 的位置 (无视并放弃了 [EBP-4] 的空间) pop ebp ; 弹栈,把刚才保存的 main 函数的 EBP 还给 EBP 寄存器 (ESP = ESP + 4) ; 此时 EBP 恢复为 main 的,ESP 指向栈顶的返回地址 ret ; 魂归故里!弹出当前栈顶的返回地址直接赋给 EIP 寄存器, ; CPU 控制权瞬间跳回 main 函数中(即 call _add 的下一行) _add endp

⚙️大佬敲黑板:
在真实的 IDA Pro 反汇编中,你经常会看到编译器把add函数尾声的mov esp, ebppop ebp两条指令合并精简为一条著名的指令:leave。它们在硬件层面上完全等价。


📊 3. 终极复习作弊表(Cheatsheet)

当你在汇编中看到以EBP为基准的内存寻址(中括号表达式)时,直接套用下表进行肉眼翻译,这是分析栈溢出(Pwn)和逆向的关键:

汇编表达式它的真实身份产生的原因Pwn 视角(漏洞安全意义)
[ebp]Saved EBP(旧 EBP 的备份)函数序言第一步push ebp留下的。栈溢出时如果把它改掉,原函数在退栈时会迷失方向,导致程序崩溃(SegFault)。
[ebp + 4]Return Address(返回地址)call指令在跳入函数前自动强行压入的。Pwn 的终极劫持目标!只要覆盖这里,就能在函数执行ret时,让程序跳去执行任意恶意代码(如 system 逻辑)。
[ebp + 8]第 1 个输入参数 (x)在返回地址的上方(高地址),由调用者提前压入。只读。改变它不会破坏栈结构,但会改变函数的业务运行逻辑。
[ebp + 12]第 2 个输入参数 (y)在第 1 个参数的上方。多个参数以此类推(+16, +20…)。只读。
[ebp - 4]第 1 个局部变量 (z)函数内部sub esp, 4之后在低地址方向自己开辟的。溢出的源头!如果这个变量是个缓冲区(如char buf[16]),当你输入过长数据时,数据会**向上(往正号/高地址方向)**依次淹没[ebp][ebp+4](返回地址)。

🧠 4. 核心逻辑闭环思维导图

高地址 (楼顶) | ... | [EBP + 12] -> 参数 2 (0xBB) <--【Caller压入】 | [EBP + 8] -> 参数 1 (0xAA) <--【Caller压入】 | [EBP + 4] -> 返回地址 (EIP) <--【CALL指令自动压入】-- 🎯 漏洞劫持核心 | [EBP] -> 旧 EBP 备份 <--【Callee序言 push ebp】 | [EBP - 4] -> 局部变量 z <--【Callee自减开辟 sub esp】-- 🌊 溢出污染源 V 低地址 (地下室)

一句话总结复习流:栈是倒着长的(向低地址生长);输入数据是顺着写的(向高地址溢出)。所以,位于低地址的局部变量一旦发生溢出,会无情地向高地址方向横扫,依次冲毁旧 EBP 和关键的返回地址。

http://www.jsqmd.com/news/1220407/

相关文章:

  • 实战idevicerestore:突破iOS固件恢复的技术边界
  • The Tower Keeps Rising:现代软件架构的复杂度边界与突围之道
  • 北京爱彼回收价格查询和靠谱平台实测排行(2026年7月最新数据) - 嘉价奢侈品回收平台
  • Excel 函数大全
  • ES6解构赋值的5个实用技巧:让JavaScript代码更简洁高效
  • 工程造价应用向量数据库
  • C2000 eQEP模块全解析:正交编码器信号处理与宽速域电机速度估算实战
  • 后缀表达式的计算是从左到右扫描表达式,遇到操作数就将其压入栈中,遇到运算符就从栈中弹出相应数量的操作数进行运算
  • 第六章 价值创造:从个体嵌入到生态共建——OPC与传统企业、产业生态、制度环境的协同进化
  • 爬虫为什么会触发验证? TLSFOWARD 抓包工具
  • 萧邦中国官方售后中心2026年7月全新400客服热线启用通知 - 亨得利腕表服务中心
  • 2026年商用卤汁批发全指南 餐饮门店适配供应商选择参考 - 麻辣烫酱料
  • BDD在AI编程中正在失效?——来自IEEE软件工程期刊的实证研究:89%团队忽略的“行为-意图-执行”三阶对齐机制
  • rtsp-stream黑名单机制:如何防止恶意请求与资源保护
  • Java程序设计(第3版)第四章——lambda表达式
  • 2026新手必看|电钢琴避坑 + 10款实测,预算万元内直接抄作业
  • 从课堂到岗位,科莱特如何打通数字化人才的“最后一公里”
  • 猫抓浏览器扩展终极指南:如何快速下载网页视频音频资源
  • MPI-IS Mesh空间搜索:AABB树与最近点查询的实战应用
  • IDELAYE2
  • 如何免费下载B站视频和番剧:BiliTools跨平台下载工具终极指南
  • 上海劳力士中国区2026年7月官方售后服务网络升级通告 统一400热线与门店新址同步启用 - 劳力士中国维修中心
  • 平均修复时间(Mean Time to Repairation, MTTR)是修复一个故障平均需要用的时间
  • R 绘图 - 条形图:从基础到进阶的完整指南与代码实例
  • 2026 保定高价回收名表靠谱商家 素君奢品汇13111597382 高价回收可上门 - GrowUME
  • PowerShellEditorServices完全指南:如何在任何编辑器中获得专业级PowerShell开发体验
  • rules_foreign_cc测试策略:如何编写可靠的外部构建集成测试
  • Talisman API参考手册:所有函数与方法的详细说明
  • EX-GAS:Unity游戏能力系统终极指南 - 从零构建专业级技能框架
  • 家门口闲置包变现,2026 易奢福覆盖厦门附近回收二手包包服务 - 奢侈品回收实体店