首页 > 编程语言 >菜鸟笔记之PWN入门(1.1.2)C程序调用过程与函数栈变化(32位 vs 64位)(Intel)

菜鸟笔记之PWN入门(1.1.2)C程序调用过程与函数栈变化(32位 vs 64位)(Intel)

时间:2024-09-18 16:26:51浏览次数:11  
标签:Intel esp 菜鸟 函数调用 vs ebp func 参数 函数

本文使用Intel 的32位为例子进行举例。64位本质上和32位类似,主要区别在于函数参数的调用方式,文章结尾会简要提及。

重新回顾一下栈pop和push指令

// 将0x50的压入栈
push 0x50

// 将esp指向的数据放入指定的寄存器中
pop 寄存器名字
比如 :pop eax
执行之后eax的值就变成了0x50

栈帧是什么?

栈帧,也就是stack frame,其本质就是一种栈,只是这种栈专门用于保存函数调用过程中的各种信息(参数,返回地址,本地变量等)。栈帧有栈顶和栈底之分,其中栈顶的地址最低,栈底的地址最高,SP(栈指针)就是一直指向栈顶的。在x86-32bit中,我们用 ebp 指向栈底,也就是基址指针;用 esp 指向栈顶,也就是栈指针。下面是一个栈帧的示意图:

// 这是一段有问题的C语言代码,仅仅只是用作C语言函数调用流程的介绍,为了方便读者理解
#include <stdio.h>

void func(参数1, 参数2 ,参数3 ) {
	
}

int main() {
    func(参数1, 参数2 ,参数3 ) ;
    return 0;
}

我们来详细分析一下上面的这个图和那一小段代码

1.其实main函数只是我们作为程序员认为的程序的入口,实际上在main函数之前编译器还会添加很多函数比如start函数等等,所以main函数的栈帧之前还是有栈帧

2.最开始进入到main函数中,还没有执行func(参数1, 参数2 ,参数3 ) ;这条代码的时候

3.func(参数1, 参数2 ,参数3 ) ; 这一条语句在汇编语言中会被翻译成为call func
而在执行call func之前程序会执行一些push指令将func函数的参数1,2,3分别压入栈中
也就是push 参数3 push 参数2 push 参数1 这三条指令。执行完之后那么栈的内容会变成这样:

4.然后参数到位了就可以执行call func了。
call func这个指令其实可以近似理解成push eip + jmp func_addr这两个指令的组合
如下图执行call func前后栈和eip指针的情况

当然图中的代码段是我自己猜测的,不够准确,因为本文的目的是介绍函数调用的过程,所以没有考虑过多只是希望尽可能简单的将整个过程讲解清楚。

5.我们已经知道了执行call func之后的eip的位置
然后我们介绍一下每个函数开头的初始化push ebpmov ebp, esp
执行 push ebp 之后

执行 mov ebp, esp 之后

我们可以看到执行了mov ebp, esp之后ebp指针esp指针指向了同一个地址,也就是ebp 旧值 所在的位置

6.在上一步中我们的espebp处于同一个位置,然后我们需要执行sub esp, 0x??(这里打?是因为我不知道具体应该减去多少),这个sub指令在这里的作用是将esp向下移动,用于开出新函数所需要的栈帧,执行之后如下图:

7.最后我们直接来看func函数的最后一条leave指令
leave指令mov esp,ebppop ebp的结合
我们来一条一条的看,先看 mov esp, ebp 执行之后的效果

这条指令会重新将espebp移动到同一个位置
然后再来看 pop ebp 执行之后的效果

我们发现此时ebp回到最初在main函数中它的位置,而esp因为pop会向上移动一格位置,来到了eip旧地址储存的位置(这是后面会提到的栈溢出的关键部分)

8.紧接着我们就会执行ret指令,这个ret指令的作用相当于 pop eip 也就是将esp现在指向的值,赋值给eip,执行完这个语句之后,我们来看看eip在哪。如图:

我们可以看到,一切都回到了call func 这个指令执行之前,只有eip的位置改变了,仿佛它从没来过...

到此为止32位程序函数的调用以及栈的变化就结束了,可以得到一个结论就是函数调用前后,栈内状况不变。其实这非常好理解,因为在一个函数中调用另外一个函数当然不能影响原函数的运行,所以的设计做到了用完就丢。被调用函数结束后espebp的位置都会回到call这个指令之前的状态,而espebp之间的数据也都没有改变
上述结论在64位中同样适用,而64位程序32位程序除了位数上不同,最大的不同就在于64位程序会优先将被调用函数的参数存放在寄存器中

这是32位函数调用:

// 这是一段有问题的C语言代码,仅仅只是用作C语言函数调用流程的介绍,为了方便读者理解
#include <stdio.h>

void func(参数1, 参数2 ,参数3 ) {
	
}

int main() {
    func(参数1, 参数2 ,参数3 ) ;
    return 0;
}

而这是64位函数调用:

// 这是一段有问题的C语言代码,仅仅只是用作C语言函数调用流程的介绍,为了方便读者理解
#include <stdio.h>

void func(参数1, 参数2 ,参数3, 参数4, 参数5 ,参数6, 参数7, 参数8) {
	
}

int main() {
    func(参数1, 参数2 ,参数3, 参数4, 参数5 ,参数6, 参数7, 参数8);
    return 0;
}

在64位程序中,函数的参数会依次放入rdi rsi rdx rcx r8 r9 这六个寄存器中,只有把这六个寄存器塞满后,才会从右到左依次放入中,像上面的代码,func函数8个参数,那么就如图所示:

注意:64位所用的是位数更多更大的RSP和RBP

总结

其实程序本身的流程并不困难,只是初学者对汇编语言的了解较少所以难以理解,如果对于文章内容难以理解,不妨寻找一些汇编语言的教程较为系统的了解汇编语言也许会有所帮助

(制作图片用的是win11自带的画图工具,里面的字体大小不知道为什么调节不了,所以出现了字体很小的情况,(。・_・。)ノI’m sorry~)

参考文献:
PWN入门(1-1-1)-C函数调用过程原理及函数栈帧分析(Intel) (yuque.com)
linux - C函数调用过程原理及函数栈帧分析 - 编程之道 - SegmentFault 思否

标签:Intel,esp,菜鸟,函数调用,vs,ebp,func,参数,函数
From: https://www.cnblogs.com/XiDP0/p/18417567

相关文章

  • 菜鸟笔记之PWN入门(1.1.0)ELF 文件格式和程序段解析(简版)
    ELF(ExecutableandLinkableFormat):是一种用于可执行文件、目标文件和库的文件格式,类似于Windows下的PE文件格式。ELF主要包括三种类型的文件:可重定位文件(relocatable):编译器和汇编器产生的 .o 文件,由 Linker 处理。可执行文件(executable): Linker ......
  • MOE vs MOT 让LLM更加有效
    知乎:北方的郎链接:https://zhuanlan.zhihu.com/p/691070810翻译自:https://www.superannotate.com/blog/mixture-of-experts-vs-mixture-of-tokens事实证明,LLM的表现与模型大小和可扩展性呈正相关。这种扩展伴随着计算资源的扩展,也就是说,模型越大,成本就越高。基于参数计......
  • vscode配置java简易教程
    一、下载jdkjava官方地址:https://www.oracle.com/java/technologies/downloads/选择适合自己电脑的版本,并下载到一个自己喜欢的地方。二、配置环境变量记住自己jdk的地址,例:我的jdk下载到了D:\app\java1、JAVA_HOME配置点击win键后,搜索“环境变量”。如图,打开配置......
  • vscode配置java简易教程
    一、下载jdkjava官方地址:https://www.oracle.com/java/technologies/downloads/选择适合自己电脑的版本,并下载到一个自己喜欢的地方。二、配置环境变量记住自己jdk的地址,例:我的jdk下载到了D:\app\java1、JAVA_HOME配置点击win键后,搜索“环境变量”。如图,打开配置......
  • 菜鸟笔记之PWN入门(1.0.0)前言
    什么是PWN?PWN是黑客术语中的俚语,是指攻破设备或者系统。它的发音类似于“砰”,当然也有师傅把它叫作“胖”。PWN的目标是获取系统的控制权或执行未经授权的操作。如何入门PWN前置知识C语言学习内容:程序结构和基础语法数据类型、分支语句(如 if、switch)和循环(如 fo......
  • 文心一言 VS 讯飞星火 VS chatgpt (349)-- 算法导论23.2 8题
    八、Borden教授提出了一个新的分治算法来计算最小生成树。该算法的原理如下:给定图,将划分为两个集合和,使得和的差最多为1。设为端点全部在中的边的集合,为端点全部在中的边的集合。我们递归地解决两个子图和的最小生成树问题。最后,在边集合中选择横跨切割和的最小权重的边来将求出的......
  • 我使用本地windows11上的VSCode远程连接到ubuntu进行RUST程序开发,我在VSCode上安装了
    当你使用VSCode的Remote-SSH扩展从本地Windows11连接到远程的Ubuntu服务器进行开发时,插件的安装有以下行为:插件的安装位置本地插件:某些插件,例如VSCode的界面插件或与本地编辑器相关的插件,安装在你的本地Windows系统上。这些插件不需要与远程服务器交互,因此它们仅......
  • 怎样在windows上使用VSCode连接到ubuntu服务器开发并调试RUST程序?
    要在Windows上使用VSCode连接到Ubuntu服务器,开发并调试Rust程序,你可以使用VisualStudioCode的Remote-SSH扩展,这个扩展可以让你通过SSH连接到远程服务器,直接在远程服务器上进行开发、调试和执行。以下是具体步骤:1.安装VSCode和必要的扩展首先,你需要在Windo......
  • 在远程的ubuntu服务器安装了rust环境,本地的windows上也安装了VSCode并且连接到了ubunt
    你已经在Ubuntu服务器上安装了Rust环境,并且在本地Windows上安装了VSCode并通过Remote-SSH扩展连接到了Ubuntu服务器。接下来,我将指导你如何在Ubuntu上创建一个Rust项目,并使用VSCode进行开发和调试。步骤1:在Ubuntu上创建Rust项目连接到Ubuntu服务器(......
  • VScode快速配置c++(菜鸟版)
    1.vscode是什么VisualStdioCode简称VSCode,是一款跨平台的、免费且开源的现代轻量级代码编辑器,支持几乎主流开发语言的语法高亮、智能代码补全、自定义快捷键、括号匹配和颜色区分、代码片段提示、代码对比等特性,也拥有对git的开箱即用的支持。同时,它还支持插件扩展,通过丰......