跳转至内容
  • 版块
  • 最新
  • 标签
  • 热门
  • Online Tools
  • 用户
  • 群组
折叠
品牌标识

D2Learn Forums

  1. 主页
  2. Blogs | 博客
  3. pinkie_ctfer's Blog
  4. C 0x01(C语言是如何进行函数调用的)

C 0x01(C语言是如何进行函数调用的)

已定时 已固定 已锁定 已移动 pinkie_ctfer's Blog
c++汇编
2 帖子 2 发布者 75 浏览
  • 从旧到新
  • 从新到旧
  • 最多赞同
登录后回复
此主题已被删除。只有拥有主题管理权限的用户可以查看。
  • 妈耶厥了妈 离线
    妈耶厥了妈 离线
    妈耶厥了
    写于 最后由 妈耶厥了 编辑
    #1

    在上一篇文章中我说错了一件事,其实没有pc寄存器,pc全称是program counter (程序计数器),他是一个抽象的概念,在x86/x64下是ip的数值(也不是很准确,在以后的文章中我们不必纠结这些事情都管他叫做PC)

    • rbp 寄存器大小
    • pc 寄存器大小

    在函数调用的时候会在栈中记录下函数调用后下一个指令的地址(pc),还会记录栈基址(rbp),这些数据记录在哪里?肯定就是内存里啦!我们再仔细看一眼汇编代码

    //C
    int testfunc(){
        int a=0;
    }
    
    int testfunc2()
    {
        testfunc();
    }
    
    
    //asm
    testfunc:
            push    rbp
            mov     rbp, rsp
            mov     DWORD PTR -4[rbp], 0
            nop
            pop     rbp
            ret
    testfunc2:
            push    rbp
            mov     rbp, rsp
            mov     eax, 0
            call    testfunc
            nop
            pop     rbp
            ret
    

    看汇编代码我们是不是看不哪里压栈了,这时候就要介绍一下call指令的执行过程

    • 首先call指令会将PC入栈
    • 然后会有一个jmp跳转到要执行的地址
      说起来可能很抽象,下面用一张图来说明他的过程
      192f617c-e6cb-4f33-9408-d58f907624f4-图片.png
      这张图片应该就可以很清晰地描绘call指令都干了些啥了吧!
      由此可见,在函数调用的过程中程序的返回地址存在栈栈中,也就是栈上的数据会影响程序的运行过程.试想如果我们修改了栈上特定位置的数值,并修改成特定的数值,那么我们就可以让程序走到意想不到的地方(栈溢出).

    32位(x86情况下)

    先上代码

    int f=0;
    int c=0;
    
    int testfunc(){
        int a=0;
        f=1;
        return c;
    }
    
    int testfunc2()
    {
        testfunc();
    }
    
    f:
            .zero   4
    c:
            .zero   4
    testfunc:
            push    ebp
            mov     ebp, esp
            sub     esp, 16
            call    __x86.get_pc_thunk.ax
            add     eax, OFFSET FLAT:_GLOBAL_OFFSET_TABLE_
            mov     DWORD PTR -4[ebp], 0
            mov     DWORD PTR f@GOTOFF[eax], 1
            mov     eax, DWORD PTR c@GOTOFF[eax]
            leave
            ret
    testfunc2:
            push    ebp
            mov     ebp, esp
            call    __x86.get_pc_thunk.ax
            add     eax, OFFSET FLAT:_GLOBAL_OFFSET_TABLE_
            call    testfunc
            nop
            pop     ebp
            ret
    __x86.get_pc_thunk.ax:
            mov     eax, DWORD PTR [esp]
            ret
    

    我们发现多了一个这个函数 __x86.get_pc_thunk.ax 这个是干什么的呢?我们来分析一下
    在testfunc2中有这样一条指令

    call    __x86.get_pc_thunk.ax
    

    首先call指令会将PC寄存器入栈,然后在 __x86.get_pc_thunk.ax 函数中进行了

      eax, DWORD PTR [esp]
    

    这个操作,esp是栈指针指向的是栈顶部也就是刚刚push的数据也就是PC寄存器的数值了,所以说这个函数是获取下一条指令的地址的,原因是因为x86架构下没有获取PC寄存器的指令只能用这种方式获取了.

    PS:为什么要这么做

    因为有一个功能叫做PIE(地址随机化)这个可以有效增加栈溢出导致REC风险
    接着来看

    add     eax, OFFSET FLAT:_GLOBAL_OFFSET_TABLE_
    

    这个 FLAT:GLOBAL_OFFSET_TABLE 是全局静态变量表所对应add指令的偏移量,这个是在编译时期确定的,所以这个代码的意思是找到全局静态变量表的地址并储存到eax寄存器中,为了方便我在下文分析函数调用的时候会关闭pie得到相对简单的汇编代码

    int testfunc(int g){
        g=8;
    }
    
    int testfunc2()
    {
        testfunc(2);
    }
    
    
    testfunc:
            push    ebp
            mov     ebp, esp
            mov     DWORD PTR [ebp+8], 8
            nop
            pop     ebp
            ret
    testfunc2:
            push    ebp
            mov     ebp, esp
            push    2
            call    testfunc
            add     esp, 4
            nop
            leave
            ret
    

    可以看到在x86下只有栈传参没有寄存器传参,其余的和x64下的是相同的

    PS:如果你想复现的话记得加入-m32 --no-pie这两个编译参数 一个是目标平台是32位的,一个是不使用pie

    1 条回复 最后回复
    1
    • sunrisepeakS 离线
      sunrisepeakS 离线
      sunrisepeak d2learn-dev
      写于 最后由 编辑
      #2

      PC寄存器基本都是有限制的, 一般可以通过间接的方式修改。而且它一般指一个逻辑上的寄存器, 可能每个架构下实现和名字有所不同。总之, 感觉记住它是存储CPU下一条要执行的指令(在机器语言中)的内存地址就可以了

      架构 PC 名称 可否直接读取 可否直接写入 位数
      x86 EIP 间接 ❌ 32
      x86_64 RIP 间接 ❌ 64
      ARM32 R15 / PC ✅ ✅ 32
      ARM64 PC ✅ ⚠️ 限制 64
      RISC-V pc ✅(模拟器) ⚠️ 部分支持 32/64
      MIPS PC ❌ ❌ 32
      PowerPC NIP ✅ ✅(特权) 32/64

      https://en.wikipedia.org/wiki/Program_counter

      1 条回复 最后回复
      0

      • 登录

      • 没有帐号? 注册

      • 登录或注册以进行搜索。
      d2learn forums Powered by NodeBB
      • 第一个帖子
        最后一个帖子
      0
      • 版块
      • 最新
      • 标签
      • 热门
      • Online Tools
      • 用户
      • 群组