汇编 call与ret 函数与堆栈 (逆向分析)

目录

源码案例

[函数调用机制概述:Call 与 Ret](#函数调用机制概述:Call 与 Ret)

[Ret 指令:函数返回](#Ret 指令:函数返回)

堆栈(Stack)基础概念

[ESP 与 EBP 寄存器详解](#ESP 与 EBP 寄存器详解)

[Push 与 Pop 指令](#Push 与 Pop 指令)

函数调用完整流程与栈帧管理

函数序言

参数访问

函数尾声

调用约定

完整示例程序(图文解释部分)

call之前的状态

保存寄存器状态

恢复esp=ebp

[pop ebp = esp+4 恢复到调用者的ebp](#pop ebp = esp+4 恢复到调用者的ebp)

[ret 执行返回函数 下一行 保存的eip寄存器](#ret 执行返回函数 下一行 保存的eip寄存器)

调用约定平栈

核心总结


源码案例

复制代码
myadd proc 
push ebp ; 使用ebp寻址 也就是上一个函数的地址 
mov ebp,esp
mov eax,[ebp+8]
mov eax,[ebp+12]
add eax,ebx
mov esp,ebp
pop ebp
ret 
myadd endp

main proc
    push 1 ; 传参
    push 2
    call myadd
    add esp,8

    invoke ExitProcess, 0
main endp
end

函数调用机制概述:Call 与 Ret

call 指令用于调用子程序(函数),其核心功能是保存返回地址并跳转到目标函数入口。

执行过程

  • 将当前 EIP(下一条指令地址,即返回地址)压入栈(等价于 push eip)。
  • 跳转到目标函数入口(类似 jmp)。

底层逻辑

复制代码
call <函数地址> 等价于 push eip; jmp <函数地址>。

Ret 指令:函数返回

ret 指令用于函数执行完毕后返回调用点。

执行过程

  • 从栈顶弹出返回地址,存入 EIP(64位为 RIP)。
  • CPU 跳转到该地址继续执行。

底层逻辑ret 等价于 pop eip

  • callret 配合实现了函数调用的"跳转-返回"机制,确保程序控制流正确恢复。

堆栈(Stack)基础概念

堆栈是一块连续的内存区域,遵循 后进先出(LIFO) 原则,用于存储临时数据、函数参数、返回地址和局部变量。

  • 栈的增长方向是向下的(地址从高到低)。
  • 栈操作主要通过 push(入栈)和 pop(出栈)完成。

ESP 与 EBP 寄存器详解

ESP(Stack Pointer,栈指针)

  • 始终指向当前栈顶。
  • push 操作时 ESP 自动减小(通常减 4 字节,32位系统)。
  • pop 操作时 ESP 自动增大。
  • 用于动态管理栈顶位置。

EBP(Base Pointer,基址指针,也称帧指针)

  • 用于固定当前函数的栈帧(stack frame)基址。
  • 函数开始时保存调用者的 EBP,然后将当前 ESP 值赋给 EBP。
  • 通过 [EBP + 偏移] 稳定访问函数参数和局部变量,不受 ESP 变化影响。

典型栈帧建立代码:

复制代码
push ebp ; 保存调用者的 EBP mov ebp, esp ; 建立新栈帧

Push 与 Pop 指令

Push(入栈)

  • 将数据压入栈顶,ESP 自动减小。
  • 用途:传递参数、保存寄存器状态、保存返回地址。

Pop(出栈)

  • 从栈顶弹出数据到寄存器或内存,ESP 自动增大。
  • 用途:恢复寄存器、获取参数或返回地址。

函数调用完整流程与栈帧管理

函数序言
复制代码
push ebp mov ebp, esp ; 可选:sub esp, N ; 分配局部变量空间
参数访问
  • [ebp + 8]:第一个参数(取决于调用约定)。
  • [ebp + 12]:第二个参数。
  • [ebp + 4]:返回地址。
  • [ebp]:调用者的 EBP。
函数尾声
复制代码
mov esp, ebp ; 释放局部变量 pop ebp ; 恢复调用者的 EBP ret ; 返回

调用约定

不同调用约定决定了参数传递顺序、谁负责清理栈(平栈):

  • _cdecl (C 默认):调用者平栈(add esp, N)。参数从右到左压栈。灵活但代码稍长。
  • _stdcall :被调用者平栈(ret N)。Windows API 常用。
  • _fastcall:前两个参数用 ECX/EDX 传递,剩余用栈。
  • thiscall :用于 C++ 成员函数,this 指针通常在 ECX。

示例(_cdecl,调用者平栈)

复制代码
main proc
    push 2            ; 第二个参数
    push 1            ; 第一个参数
    call myadd
    add esp, 8        ; 调用者平栈(2个参数 × 4字节)
    ...
main endp

完整示例程序(图文解释部分)

call之前的状态
保存寄存器状态
恢复esp=ebp
pop ebp = esp+4 恢复到调用者的ebp
ret 执行返回函数 下一行 保存的eip寄存器
调用约定平栈

核心总结

  • Call/Ret 是函数调用的核心:call 压返回地址并跳转,ret 弹返回地址并返回。
  • ESP 是动态栈顶指针,EBP 是稳定栈帧基址。
  • 栈帧通过 push ebp / mov ebp,esp 建立,通过 mov esp,ebp / pop ebp 恢复。
  • 参数传递依赖调用约定,注意压栈顺序和平栈责任。
  • 正确维护栈平衡是避免程序崩溃的关键(栈溢出、返回地址破坏等常见错误)。

掌握这些基础后,你就能清晰理解 x86 汇编中函数调用、参数传递和栈帧管理的底层机制,为进一步学习逆向

相关推荐
山屿落星辰5 小时前
昇腾NPU算子开发:从“手写汇编“到“搭积木“
汇编
BestOrNothing_20159 小时前
C++零基础到工程实战(5.1):初识函数—定义调用、参数返回值、栈区内存与变量作用域分析
c++·生命周期·作用域·变量·函数·栈内存
浩浩测试一下10 小时前
汇编 汇编寻址 (逆向分析)
汇编·寻址·windows编程·二进制逆向·机器码
浩浩测试一下1 天前
汇编 位运算 (逆向分析)
汇编·逆向·位运算·asm·windows编程·二进制逆向
浩浩测试一下1 天前
汇编 高低八位寄存器数据存储方式(逆向分析)
汇编·网络安全·逆向·二进制·免杀·寄存器·windows编程
a83331961 天前
C语言嵌入汇编详解
汇编·单片机·语言
yoyo_zzm2 天前
汇编到PHP:五大编程语言核心特性全解析
开发语言·汇编·php
谷哥的小弟2 天前
(最新版)Git&GitHub实操图文详解教程(04)—远程仓库GitHub
git·github·pull·push·版本管理·版本控制
ComputerInBook4 天前
X64 汇编 MOVSD 的两种用法
汇编·汇编指令·movsd