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

CTF-RE 从0到N:汇编层函数调用

windows

在 Windows 平台上的汇编语言中,调用函数的方式通常遵循特定的调用约定(Calling Convention)。最常见的调用约定包括:

  • cdecl: C 默认调用约定,调用者清理堆栈。
  • stdcall: Windows API 默认调用约定,被调用者清理堆栈。
  • fastcall: 使用寄存器传递前两个参数,其余参数通过堆栈传递。
  • x64: 在 64 位系统上,使用寄存器传递前四个参数,其余参数通过堆栈传递。

1. cdecl 调用约定

在 cdecl 调用约定中,函数参数从右到左推入堆栈,函数返回后由调用者清理堆栈。

; 函数原型: int add(int a, int b);
push    dword ptr [b]   ; 将参数 b 推入堆栈
push    dword ptr [a]   ; 将参数 a 推入堆栈
call    add             ; 调用函数 add
add     esp, 8          ; 调用者清理堆栈 (2 * 4 bytes)

2. stdcall 调用约定

在 stdcall 调用约定中,函数参数同样从右到左推入堆栈,但由被调用者清理堆栈。

; 函数原型: int add(int a, int b);
push    dword ptr [b]   ; 将参数 b 推入堆栈
push    dword ptr [a]   ; 将参数 a 推入堆栈
call    add             ; 调用函数 add
; 不需要清理堆栈,因为被调用者会清理堆栈

3. fastcall 调用约定

在 fastcall 调用约定中,前两个参数通过寄存器传递(ECX 和 EDX),其余参数通过堆栈传递。

; 函数原型: int add(int a, int b);
mov     ecx, dword ptr [a]   ; 将参数 a 放入 ECX 寄存器
mov     edx, dword ptr [b]   ; 将参数 b 放入 EDX 寄存器
call    add                  ; 调用函数 add
; 不需要清理堆栈,因为被调用者会清理寄存器

4. x64 调用约定

在 64 位系统的 Windows 上,前四个参数通过寄存器传递,后续参数通过堆栈传递。惯例使用的寄存器是:RCX、RDX、R8 和 R9。

; 函数原型: int add(int a, int b, int c, int d);
mov     ecx, dword ptr [a]   ; 将参数 a 放入 RCX 寄存器
mov     edx, dword ptr [b]   ; 将参数 b 放入 RDX 寄存器
mov     r8d, dword ptr [c]   ; 将参数 c 放入 R8 寄存器
mov     r9d, dword ptr [d]   ; 将参数 d 放入 R9 寄存器
call    add                  ; 调用函数 add
; 返回值在 RAX 寄存器中

具体例子

假设我们有一个简单的 C 函数:

int add(int a, int b) {return a + b;
}
使用 cdecl 调用约定的实现:
section .dataa dd 5b dd 10section .textextern addglobal _start_start:push    dword [b]       ; 推入参数 bpush    dword [a]       ; 推入参数 acall    add             ; 调用函数 addadd     esp, 8          ; 清理堆栈mov     ebx, eax        ; 将返回值存入 EBX(假设退出码)mov     eax, 1          ; 系统调用号 (sys_exit)int     0x80            ; 调用内核
使用 x64 调用约定的实现:
section .dataa dd 5b dd 10section .textextern addglobal _start_start:mov     ecx, dword [a]  ; 将参数 a 放入 RCXmov     edx, dword [b]  ; 将参数 b 放入 RDXcall    add             ; 调用函数 add; 返回值在 RAX 寄存器中mov     edi, eax        ; 将返回值存入 EDI(假设退出码)mov     eax, 60         ; 系统调用号 (sys_exit)syscall                 ; 调用内核

linux

基本

在汇编语言中,调用函数的过程涉及多个步骤,包括参数传递、调用指令、堆栈管理和返回值处理。下面详细解释在x86架构的汇编语言中,调用函数的过程,特别是基于C语言的函数调用约定。

函数调用约定

函数调用约定定义了如何在汇编中传递参数、管理堆栈以及返回值。不同系统和编译器有不同的调用约定,如cdeclstdcallfastcall 等。我们以最常见的cdecl调用约定为例。

函数调用的主要步骤
  1. 参数压栈

    • 在调用函数前,参数按照从右到左的顺序压入栈中。
    • 这意味着第一个参数最后压栈,最后一个参数最先压栈。
  2. 调用指令 call

    • 使用 call 指令调用函数。call指令会做两件事:
      1. 将下一条指令(即函数调用后紧跟的指令地址)压入栈中,作为返回地址。
      2. 跳转到被调用函数的地址。
  3. 函数内部处理

    • 进入函数后,通常会创建一个新的栈帧,通过 push ebp 保存调用者的栈帧指针,然后 mov ebp, esp 设置当前栈帧指针。
    • 函数从栈中读取参数,并执行操作。
  4. 返回值

    • 返回值通常存储在 eax 寄存器中。
  5. 清理栈

    • 函数返回后,调用者负责清理栈上压入的参数。对于 cdecl 调用约定,调用者负责清理栈。
    • 对于 stdcall 调用约定,函数自己清理参数。
汇编代码中的调用过程

我们通过一个具体的汇编调用过程来解释:

push    arg2    ; 第二个参数压栈
push    arg1    ; 第一个参数压栈
call    function_name ; 调用函数
add     esp, 8  ; 调用者清理栈上的参数 (两个参数,每个参数4字节,总共8字节)
具体例子

假设我们有一个简单的 C 函数:

int add(int a, int b) {return a + b;
}int main() {int result = add(3, 4);return 0;
}

对应的汇编代码(简化版)可能如下:

; 在 main 函数中:
push    4               ; 第二个参数 b = 4 压栈
push    3               ; 第一个参数 a = 3 压栈
call    add             ; 调用 add 函数
add     esp, 8          ; 清理栈(2个参数,每个4字节)
mov     [ebp-4], eax    ; 将结果存入局部变量 result; 在 add 函数中:
add procpush    ebp         ; 保存调用者的栈帧mov     ebp, esp    ; 设置当前栈帧mov     eax, [ebp+8] ; 加载第一个参数 amov     ecx, [ebp+12] ; 加载第二个参数 badd     eax, ecx    ; 执行加法pop     ebp         ; 恢复调用者的栈帧ret                 ; 返回,结果在 eax 中
add endp

详细步骤说明

  1. 参数压栈

    • push 4push 3 将两个参数 43 压入栈,按照从右到左的顺序。
  2. 调用函数

    • call add 调用 add 函数。call 指令会将下一条指令的地址压入栈中,作为返回地址,并跳转到 add 函数的地址执行。
  3. 函数栈帧设置

    • add 函数中,push ebp 将调用者的栈帧指针保存到栈中。
    • mov ebp, esp 设置当前函数的栈帧指针,使得栈指针 esp 成为当前函数的栈帧基准。
    • mov eax, [ebp+8] 加载第一个参数 a,它位于栈中距离 ebp 8 个字节的位置(4字节是保存的 ebp,再往上是返回地址)。
    • mov ecx, [ebp+12] 加载第二个参数 b,它位于 ebp+12 位置。
  4. 执行加法

    • add eax, ecx 将参数 ab 相加,结果存入 eax 寄存器。
  5. 函数返回

    • pop ebp 恢复调用者的栈帧。
    • ret 从函数返回,eax 中的值作为返回值传递回调用者。
  6. 调用者清理栈

    • add esp, 8 调用者负责清理栈上压入的两个参数,共8个字节。

总结

函数调用在汇编中的实现依赖于:

  • 参数压栈:参数按从右到左顺序压入栈中。
  • 调用函数call 指令将返回地址压栈并跳转到函数地址。
  • 栈帧管理:函数通常会创建自己的栈帧,使用 ebp 寄存器管理。
  • 返回值传递:返回值通常存储在 eax 寄存器中。
  • 清理栈:根据调用约定,调用者或被调用者负责清理栈上的参数。

通过这个过程,我们可以理解函数在低级汇编语言中的调用机制如何运作。

拥有可变参数的函数

对于可变参数函数(例如 C 语言中的 printf),在汇编中调用可变参数函数的过程与普通函数调用稍有不同,因为需要处理不确定数量的参数。stdarg.h 中的宏(例如 va_start, va_arg, va_end)用于处理这些可变参数。

我们以 int a(char *Format, ...) 这种可变参数函数为例,来说明汇编中如何处理可变参数函数。

可变参数的处理

当一个函数定义为可变参数(即包含 ...),在汇编中,通常需要根据栈的布局和函数的调用约定手动管理这些参数。x86 调用约定(例如 cdecl)中,可变参数会和固定参数一起压入栈中。

int a(char *Format, ...) 为例,它的汇编调用流程与普通函数类似,但需要特别处理可变参数。

函数调用过程

参数压栈

调用函数时,已知的参数(如 Format)按照普通参数顺序压栈,之后才压入可变参数。可变参数通过栈传递。

例如,假设我们调用如下的 C 代码:

int a(char *Format, ...) {// 实现略
}int main() {a("%d %s", 42, "example");
}

在汇编中,参数传递的顺序如下(以 cdecl 调用约定为例):

push    offset string_example  ; 可变参数 "example"
push    42                     ; 可变参数 42
push    offset format_string   ; 固定参数 Format
call    a                      ; 调用可变参数函数
add     esp, 12                ; 清理栈(3个参数,每个4字节,共12字节)
函数内部处理

函数在内部使用 va_start 等宏来访问可变参数,这在汇编中是通过对栈指针的操作来完成的。

以下是可能的汇编流程:

  1. 设置栈帧

    • 和普通函数一样,先保存调用者的栈帧,设置当前栈帧:
      push    ebp
      mov     ebp, esp
      
  2. 访问固定参数

    • 在栈中,Format 是第一个参数,位于 [ebp + 8] 处。
      mov     eax, [ebp + 8]     ; 获取 Format 参数
      
  3. 初始化可变参数列表

    • 使用 lea(Load Effective Address)指令计算可变参数列表的起始地址。通常第一个可变参数位于 [ebp + 12],即在第一个固定参数之后:
      lea     ecx, [ebp + 12]    ; 计算可变参数列表的地址
      
  4. 调用处理函数

    • Format 和可变参数列表的地址传递给实际处理函数,类似于 vprintf 这样的函数。
      push    ecx                ; 压入可变参数地址
      push    eax                ; 压入 Format 字符串
      call    vprintf            ; 调用变参处理函数
      
  5. 清理栈并返回

    • 函数执行完毕后,需要恢复栈指针并返回。
      pop     ebp
      ret
      

完整的汇编示例

假设我们要实现一个简单的 int a(char *Format, ...) 函数,它只将格式化字符串和可变参数传递给 vprintf。以下是它的汇编实现的简化版本:

a procpush    ebp                ; 保存调用者的栈帧mov     ebp, esp           ; 设置当前栈帧mov     eax, [ebp + 8]     ; 获取第一个参数 Format(位于栈中第一个固定参数位置)lea     ecx, [ebp + 12]    ; 获取可变参数列表的地址push    ecx                ; 将可变参数地址压栈push    eax                ; 将 Format 压栈call    vprintf            ; 调用 vprintf 函数pop     ebp                ; 恢复栈帧ret                        ; 返回a endp

对应的 C 实现

对应的 C 实现如下所示,使用 va_startva_end 等标准宏来处理可变参数:

#include <stdio.h>
#include <stdarg.h>int a(const char *Format, ...) {va_list args;va_start(args, Format);     // 初始化可变参数列表int result = vprintf(Format, args);  // 将 Format 和可变参数传递给 vprintfva_end(args);               // 清理可变参数列表return result;
}int main() {a("%d %s\n", 42, "example");return 0;
}

总结

在可变参数函数的汇编实现中:

  1. 参数传递

    • 固定参数(如 Format)和可变参数按顺序压入栈中。
    • 可变参数通过栈传递,函数内部通过栈指针访问这些参数。
  2. 处理可变参数

    • 函数通过计算堆栈中的地址来获取可变参数列表的起始位置(通常通过 [ebp + offset] 来计算)。
  3. 调用内部的处理函数

    • 使用汇编中的 lea 指令计算可变参数列表的地址,并传递给诸如 vprintf 这样的变参处理函数。

相关文章:

CTF-RE 从0到N:汇编层函数调用

windows 在 Windows 平台上的汇编语言中&#xff0c;调用函数的方式通常遵循特定的调用约定&#xff08;Calling Convention&#xff09;。最常见的调用约定包括&#xff1a; cdecl: C 默认调用约定&#xff0c;调用者清理堆栈。stdcall: Windows API 默认调用约定&#xff0…...

雷池社区版compose配置文件解析-mgt

在现代网络安全中&#xff0c;选择合适的 Web 应用防火墙至关重要。雷池&#xff08;SafeLine&#xff09;社区版免费切好用。为网站提供全面的保护&#xff0c;帮助网站抵御各种网络攻击。 compose.yml 文件是 Docker Compose 的核心文件&#xff0c;用于定义和管理多个 Dock…...

无人机避障——4D毫米波雷达Octomap从点云建立三维栅格地图

Octomap安装 sudo apt-get install ros-melodic-octomap-ros sudo apt-get install ros-melodic-octomap-msgs sudo apt-get install ros-melodic-octomap-server sudo apt-get install ros-melodic-octomap-rviz-plugins # map_server安装 sudo apt-get install ros-melodic-…...

Python(数据结构2)

常见数据结构 队列 队列(Queue)&#xff0c;它是一种运算受限的线性表,先进先出(FIFO First In First Out) Python标准库中的queue模块提供了多种队列实现&#xff0c;包括普通队列、双端队列、优先队列等。 1 普通队列 queue.Queue 是 Python 标准库 queue 模块中的一个类…...

深入解析HTTP与HTTPS的区别及实现原理

文章目录 引言HTTP协议基础HTTP响应 HTTPS协议SSL/TLS协议 总结参考资料 引言 HTTP&#xff08;HyperText Transfer Protocol&#xff09;超文本传输协议是用于从Web服务器传输超文本到本地浏览器的主要协议。随着网络安全意识的提高&#xff0c;HTTPS&#xff08;HTTP Secure…...

Java IO 模型

I/O 何为 I/O? I/O&#xff08;Input/Output&#xff09; 即输入&#xff0f;输出 。 我们先从计算机结构的角度来解读一下 I/O。 根据冯.诺依曼结构&#xff0c;计算机结构分为 5 大部分&#xff1a;运算器、控制器、存储器、输入设备、输出设备。 输入设备&#xff08;比…...

安装双系统后ubuntu无法联网(没有wifi标识)网卡驱动为RTL8852BE

安装双系统后ubuntu没有办法联网&#xff0c;&#xff08;本篇博客适用的版本为ubuntu20.04&#xff09;且针对情况为无线网卡驱动未安装的情况 此时没有网络&#xff0c;可以使用手机数据线连接&#xff0c;使用USB共享网络便可解决无法下载的问题。 打开终端使用命令lshw -C …...

Sqoop的安装配置及使用

Sqoop安装前需要检查之前是否安装了Tez,否则会产生版本或依赖冲突&#xff0c;我们需要移除tez-site.xml&#xff0c;并将hadoop中的mapred-site.xml配置文件中的mapreduce驱动改回成yarn&#xff0c;然后分发到其他节点&#xff0c;hive里面配置的tez也要移除&#xff0c;然后…...

R语言机器学习算法实战系列(十三)随机森林生存分析构建预后模型 (Random Survival Forest)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍教程加载R包案例数据数据预处理数据描述构建randomForestSRC模型评估模型C-indexBrier score特征重要性构建新的随机森林生存模型风险打分高低风险分组的生存分析时间依赖的ROC(Ti…...

三款计算服务器配置→如何选择科学计算服务器?

科学计算在众多领域都扮演着关键角色&#xff0c;无论是基础科学研究还是实际工程应用&#xff0c;强大的计算能力都是不可或缺的。而选择一台合适的科学计算服务器&#xff0c;对于确保科研和工作的顺利进行至关重要。 首先&#xff0c;明确自身需求是重中之重。要仔细考虑计算…...

Oracle 19c RAC删除多余的PDB的方式

文章目录 一、删除PDB并删除数据文件二、删除PDB并保留数据文件三、插拔PDB 一、删除PDB并删除数据文件 所删除的pdb必须是mount的状态才可以删除&#xff1a; #1、关闭pdb alter pluggable database pdb_name close immediate instancesall; #2、删除pdb以及数据文件 drop p…...

什么是云渲染?云渲染有什么用?一篇看懂云渲染意思

你知道云渲染是怎么回事吗&#xff1f; 其实就是把3D模型变成2D图像的过程&#xff0c;只不过这个过程是在云端完成的。我们在本地啥都不用做&#xff0c;只需要等结果就行。 现在云渲染主要有两种类型&#xff1a;一种是物理机房云渲染&#xff0c;另一种是服务器机房云渲染。…...

MATLAB中 exist函数用法

目录 语法 说明 示例 检查工作区变量是否存在 检查文件夹是否存在 检查 MATLAB 函数是否为内置函数 exist函数的功能是检查变量、脚本、函数、文件夹或类的存在情况。 语法 exist name exist name searchType A exist(___) 说明 exist name 以数字形式返回 name 的类…...

在银河麒麟系统中Qt连接达梦数据库

解决在银河麒麟系统中使用Qt连接达梦数据库提示&#xff1a;project Error library odbc is not defined问题 一、编译ODBC 下载解压unixODBC&#xff08;http://www.unixodbc.org/unixODBC-2.3.1.tar.gz&#xff09; 打开终端&#xff0c;切换到unixODBC-2.3.1目录下&#x…...

nodejs 服务器实现负载均衡

server.js const express require(express); const { createProxyMiddleware } require(http-proxy-middleware); const axios require(axios);const app express();// 定义后端服务列表 const services [{ target: http://localhost:3001 },{ target: http://localhost:…...

今日总结10.29

常见序列化协议有哪些 序列化&#xff08;serialization&#xff09;是将对象序列化为二进制形式&#xff08;字节数组&#xff09;&#xff0c;一般也将序列化称为编码&#xff08;Encode&#xff09;&#xff0c;主要用于网络传输、数据持久化等。常见的序列化协议包括以下几…...

使用 FastGPT 工作流实现 AI 赛博算卦,一键生成卦象图

最近那个男人写的汉语新解火遍了全网&#xff0c;那个男人叫李继刚&#xff0c;国内玩 AI 的同学如果不知道这个名字&#xff0c;可以去面壁思过了。 这个汉语新解的神奇之处就在于它只是一段几百字的提示词&#xff0c;效果却顶得上几千行代码写出来的应用程序。 这段提示词…...

vue3+ts实时播放视频,视频分屏

使用vue3以及播放视频组件Jessibuca Jessibuca地址 使用循环个数来实现分屏 效果图&#xff0c;四屏 九屏 dom代码 <div class"icon"><div class"icon-box"><span class"text">分屏&#xff1a;</span><el-icon …...

【网页设计】学成在线案例

Demo 典型的企业级网站&#xff0c;目的是为了整体感知企业级网站的布局流程&#xff0c;复习以前知识。 集合代码见文章最后。 5.1 准备素材和工具 学成在线 PSD 源文件。开发工具 PS&#xff08;切图&#xff09; sublime&#xff08;代码&#xff09; chrome&#xff0…...

一篇文章总结 SQL 基础知识点

1. 官方文档 MySQL&#xff1a;https://dev.mysql.com/doc/refman/8.4/en/ SQL Server&#xff1a;What is SQL Server? - SQL Server | Microsoft Learn Oracle&#xff1a;https://docs.oracle.com/en/database/oracle/oracle-database/23/lnpls/loe.html 2. 术语 SQL S…...

告别DDA!用Python手撸Bresenham画线算法,从原理到实现(附完整源码)

告别DDA&#xff01;用Python手撸Bresenham画线算法&#xff0c;从原理到实现&#xff08;附完整源码&#xff09; 在计算机图形学领域&#xff0c;直线绘制是最基础却至关重要的操作。当你需要开发一个2D图形引擎、像素画工具或是任何需要精确控制像素显示的应用程序时&#x…...

Axure RP中文界面完全指南:4步实现高效设计工作流

Axure RP中文界面完全指南&#xff1a;4步实现高效设计工作流 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包&#xff0c;不定期更新。支持 Axure 9、Axure 10。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 作为产…...

不是删改,是升级:百考通智能降重+降AI,让语言更学术、更像“你”

在一个人工智能可以生成论文的时代&#xff0c;最荒诞的现实不是机器冒充人类&#xff0c; 而是人类因写得太像“一篇合格的学术论文”&#xff0c;被当作AI。 2026年&#xff0c;无数普通学子正陷入一场无声的困境&#xff1a; 你没用任何代写&#xff0c;却因逻辑清晰被系统…...

OpenClaw+GLM-4.7-Flash成本对比:自建模型比API调用节省30%token消耗

OpenClawGLM-4.7-Flash成本对比&#xff1a;自建模型比API调用节省30%token消耗 1. 为什么需要关注token消耗 上周五凌晨两点&#xff0c;我的OpenClaw突然停止了周报自动化任务。查看日志发现是API额度耗尽——当月累计消耗已超过商用GLM-4.7-Flash的套餐限额。这次意外让我…...

Windows 11下用VSCode+CMake+MinGW编译OpenCV 4.8.0,保姆级避坑指南

Windows 11下用VSCodeCMakeMinGW编译OpenCV 4.8.0全流程实战 最近在Windows 11上配置OpenCV开发环境时&#xff0c;发现很多教程都存在版本过时或Win11特有兼容性问题。本文将分享一套经过验证的最新工具链组合&#xff1a;VSCode 1.85CMake 3.28MinGW-w64 12.2OpenCV 4.8.0。不…...

【八股必备】多线程面试题2

第一部分&#xff1a;线程基础与概念篇1. 线程模型面试官&#xff1a;先来个基础题&#xff0c;Java程序里的线程和操作系统线程是什么关系&#xff1f;是一回事吗&#xff1f;候选人&#xff1a;好的。在绝大多数情况下&#xff0c;比如我们常用的Windows、Linux系统&#xff…...

Qwen3-0.6B-FP8惊艳效果:Qwen3-0.6B-FP8在中文法律条文理解任务中表现优异

Qwen3-0.6B-FP8惊艳效果&#xff1a;在中文法律条文理解任务中表现优异 最近&#xff0c;我在测试一个非常有意思的模型——Qwen3-0.6B-FP8。你可能听说过各种大模型&#xff0c;但这个模型有点特别&#xff0c;它是个“小个子”&#xff0c;却想在“大任务”上证明自己。我把…...

法律文书助手:OpenClaw+Qwen3-32B的合同条款审查与风险提示

法律文书助手&#xff1a;OpenClawQwen3-32B的合同条款审查与风险提示 1. 为什么需要本地化的法律文书助手&#xff1f; 去年处理一份股权投资协议时&#xff0c;我经历了传统法律AI工具的典型痛点&#xff1a;上传合同到第三方平台后&#xff0c;法务团队突然发现协议中涉及…...

云容笔谈·东方红颜影像生成系统与ComfyUI工作流集成:可视化节点式创作

云容笔谈东方红颜影像生成系统与ComfyUI工作流集成&#xff1a;可视化节点式创作 如果你是一位数字艺术家或者技术美术&#xff0c;可能常常面临这样的困境&#xff1a;你有一个绝佳的创意&#xff0c;比如想生成一幅融合了东方古典美学与现代光影的“红颜”肖像&#xff0c;但…...

Phi-4-Reasoning-VisionGPU算力:双卡4090推理吞吐达12 token/s实测

Phi-4-Reasoning-VisionGPU算力&#xff1a;双卡4090推理吞吐达12 token/s实测 1. 项目概述 Phi-4-Reasoning-Vision是一款基于微软Phi-4-reasoning-vision-15B多模态大模型开发的高性能推理工具。该工具专为双卡RTX 4090环境优化&#xff0c;通过精心设计的架构和优化策略&a…...