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

第一周:底层筑基——x86汇编与栈帧深度解析

网安寒假第一周学习笔记

一.实验环境搭建

为了能够清晰地观察程序在底层的运行逻辑,本周我完成了以下环境配置:

1. 工具选择:Visual Studio 2010 (中文版)
2. 核心编译配置
模式选择Debug(调试)模式

原因:Release 模式下,编译器会开启优化(如 O2 优化),可能会直接删掉未使用的局部变量,或者将简单的函数调用改为内联,导致我们在反汇编窗口看不到预期的指令。

架构选择x86 (Win32)

原因:本次任务重点学习 32 位汇编指令集及寄存器(EAX, EBX, ESP, EBP 等)。

3. 调试窗口准备
  • 反汇编窗口 (Disassembly):通过 右键 -> 转到反汇编 进入,是观察 C 代码与汇编代码对应关系的桥梁。

  • 寄存器窗口 (Registers):实时观察 EAX、ESP、EBP 以及标志位的变化,验证指令执行效果。

  • 内存窗口 (Memory):配合局部变量地址,观察数据在栈内存中的真实存储形态(如十六进制显示)。

二. 常用指令集解析与实验观察

在vs2010中写了一个基础的c语言程序,用于探究几类核心指令的功能及它们对寄存器/栈的影响

#include <stdio.h> int add(int x, int y) { int sum = x + y; return sum; } int main() { int a = 5; int b = 10; int result = add(a, b); printf("Result: %d\n", result); return 0; }

对该程序进行调试,可以得到

1. 数据传送:mov 与 lea
  • mov (Move)

    • 指令示例:mov eax, dword ptr [b]

    • 观察总结:最常用的赋值指令。将内存中变量 b 的值传送到 eax 寄存器。注意 dword ptr 表示操作的是 4 字节数据。

  • lea (Load Effective Address)

    • 指令示例:lea edi, [ebp-0E4h]

    • 观察总结取地址指令。它不搬运内存里的数据,而是把计算好的地址算出来给寄存器。这在建立栈帧预留局部变量空间时非常常见。

2. 算术运算:add 与 sub
  • add (Add)

    • 指令示例:add eax, dword ptr [ebp-14h]

    • 观察总结:加法运算。在函数返回前,常看到 add esp, 8,这代表栈平衡操作,手动释放之前压入栈的参数空间。

  • sub (Subtract)

    • 指令示例:sub esp, 0E4h

    • 观察总结:减法运算。在函数开头,通过减小 esp(栈顶指针)的值,为当前函数开辟局部变量所需的“空房”。

3. 栈操作:push 与 pop (核心)
  • push (Push onto Stack)

    • 动作:ESP 减小 4,然后将数据存入 ESP 指向的地址。

    • 实验观察:在调用 add(a, b) 之前,程序执行了两次 push。我观察到每执行一次 push,寄存器窗口中的 ESP 值就减小了 4。

  • pop (Pop from Stack)

    • 动作:从 ESP 指向的地址取出数据放入寄存器,然后 ESP 增加 4。

    • 实验观察:常用于函数结尾恢复 ebp 或其他寄存器的值。

4. 流程控制:call、ret、jmp 与 cmp
  • call (Call Function)

    • 功能:调用函数。它会先将当前的返回地址(即 call 指令的下一条指令地址)压入栈中,然后跳转到目标函数地址。

  • ret (Return)

    • 功能:函数返回。从栈顶弹出之前保存的返回地址,并跳转回去,继续执行主程序。

  • cmp (Compare) 与 jmp (Jump)

    • 观察总结:cmp 常用于比较两个数(本质是做减法但不保存结果,只改标志位)。根据 cmp 的结果,配合 je/jne/jmp 等指令实现程序的跳转逻辑(如 if 语句)。

三. 函数栈帧(Stack Frame)深度剖析

通过对 main 函数和 add 函数的观察,我深入理解了程序是如何在堆栈中为函数开辟空间的。

1. 函数的“开场”:

每个函数在执行真正的代码之前,都会执行一段固定的汇编指令来初始化自己的栈帧。

  • push ebp:将上一个函数的基址(EBP)保存到栈中,方便以后返回。

  • mov ebp, esp最关键的一步。将当前的栈顶(ESP)作为新函数的基址(EBP)。从此以后,EBP 就像一个“锚点”,固定不动,用于定位参数和局部变量。

  • sub esp, 0E4h:将栈顶指针向上(低地址方向)移动,预留出足够的空间来存放局部变量。

2. 栈中数据的定位:EBP 的“十字坐标”

在函数执行期间,ESP(栈顶)会随着 push 和 pop 不断上下跳动,而 EBP 一旦在 Prologue 中固定好,就再也不动了

在 x86 架构下,栈是向低地址增长的。而函数参数是在 call 指令执行之前就被 push 进栈的,所以它们的内存地址比当前的 ebp 更

  • [ebp + 4]:存放的是返回地址(Return Address)。这是 call 指令自动压入的,函数执行完后就靠它跳回主程序。

  • [ebp + 8]:存放的是第一个参数

  • [ebp + 12] (即 ebp + 0Ch):存放的是第二个参数

  • 规律:ebp + 4 * (n + 1) 就是第 n 个参数。

局部变量是函数通过 sub esp, XXX 预留出来的空间,这些空间位于当前 ebp 的下方(内存地址更低)。

  • [ebp - 4]:存放的是第一个局部变量

  • [ebp - 8]:存放的是第二个局部变量

  • 规律:你在 C 语言里定义的 int a, b, c;,在汇编里就会变成 [ebp-4], [ebp-8], [ebp-0Ch]。

EBP 就像是函数内部的“指南针”,EBP + 找外界传进来的东西,EBP - 找函数自己产生的东西。

3. 栈空间的初始化:

在 sub esp 之后,我观察到一段很有趣的代码:

这段代码的作用是将刚才开辟的 0xE4 字节空间全部填充为 0xCC。这解释了 C 语言中一个经典现象:如果变量没有手动初始化就直接打印,会输出“烫烫烫”,因为 0xCCCC 在 GBK 编码中对应的汉字正是“烫”。

为了验证上述 rep stos 指令的执行结果,我打开了 VS2010 的内存窗口进行观察。如下图所示,可以看到预留的栈空间确实被整齐地填充为了 0xCC:

4. 函数的“退场”:

当函数执行完毕,需要将栈恢复原样,否则主程序会崩溃:

  • mov esp, ebp:直接让栈顶回到基址,瞬间丢弃所有局部变量。

  • pop ebp:从栈中弹出之前保存的“老栈底”,恢复上一个函数的基址。

  • ret:从栈顶取出返回地址,跳回主程序。

  • add esp, 8(在主程序中):因为主程序之前 push 了两个参数(共 8 字节),现在手动把 ESP 拨回 8 字节的位置,这叫由调用者负责的栈平衡

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

相关文章:

  • Keil MDK 5.39 编程 + 调试 ,ARM 嵌入式开发!如何安装 - 教程
  • 15. GPU的SM简介
  • 01. GUIContent
  • 14. GPU共享内存
  • 前端+AI:CSS3(二) - 指南
  • 都在推deepseek本地化部署,为什么我不建议!
  • 别只盯着deepseek了,这个大模型本地化部署成本仅deepseek的1/3
  • day83(2.11)——leetcode面试经典150
  • 智能风控新纪元:建广数科自主开发的风险监控平台
  • 深入解析 Rust 数据建模:枚举(Enum)与结构体(Struct)的深度设计与工程实践 - 实践
  • Redis 8.6新特性全解析:从性能到运维的升级
  • 《构建之法》读后感(2)
  • list文档介绍。 - 教程
  • Java高频面试题:ZooKeeper集群中服务器之间是怎样通信的?
  • OpenFeign全解 声明式REST客户端原理与配置实战
  • D.二分查找-二分答案-求最大——1802. 有界数组中指定下标处的最大值
  • 别再用ChatGPT群发祝福了!30分钟微调一个懂你关系的“人情味”拜年AI
  • python defaultdict
  • A.每日一题——1382. 将二叉搜索树变平衡
  • 一人食调味痛点破解:小容量健康调味品,告别凑活吃出精致感 - 谈谈-新视野
  • 计算机毕业设计springboot医疗纠纷处理系统 医患矛盾调解信息化平台的设计与实现 医疗事故争议在线处置系统的设计与开发
  • B3872 [GESP202309 五级] 巧夺大奖
  • 信息论与编码篇---微分熵
  • 2深度学习基础知识
  • 独居餐如何有仪式感?天然提鲜调味品,让一人食告别凑活 - 谈谈-新视野
  • 信息论与编码篇---微分熵的极值性
  • 一人食不将就:轻盐调味让独居餐吃出健康与仪式感 - 谈谈-新视野
  • 自定义控件 - 流式布局:TagFlowLayout
  • 信息论与编码篇---连续随机变量的微分熵
  • 六个月慢酿的轻盐调味品,适配一人食的健康选择 - 谈谈-新视野