谁调用了main?

作者: 罗蓁蓁 | 来源:发表于2020-04-28 19:30 被阅读0次

    这是函数帧的应用之一。

    操作可行性

    从上一篇中可以发现:用帧指针 ebp 可以回溯到所有的函数帧,那么 main 函数帧之上的函数帧自然也是可以的;而帧中 旧ebp 的上一个四字节存的是函数的返回地址,由这个地址我们可以判断出谁调用了这个函数。

    准备活动

    下面就是这次黑客行动的主角(up.c):

    #include <stdio.h>
    int main()
    {
        int *p;
        
        // 以下这行内联汇编将 ebp 寄存器的值存到指针 p 中
        __asm__("movl %%ebp, %0"
                :"=m"(p));
        
        while(p != NULL){
            printf("%p\n", p[1]);
            p = (int*)(p[0]);
        }
        
        return 0;
    }
    

    首先,请允许我使用一下 gcc 内联汇编,这里简单的解释一下:

    1. "=m"(p) 表示将内存变量 p 作为一个输出操作数
    2. %0 代表的是第一个操作数,那就是 p 了
    3. 为了与操作数区别开来,寄存器要多加个 %,%%ebp 表示的就是 ebp 寄存器

    总之,这块内联汇编将 ebp 寄存器的值赋给了指针 p。

    然后解释一下while循环:循环中,首先打印 p[1],p[1]就是该帧所存的返回地址;然后将指针 p 改为 p[0],p[0]是 旧ebp(上一帧的帧指针);

    这样,程序将按照调用顺序的逆序打印出各个返回地址。

    为什么终止条件是 p==NULL 呢?这是 gcc 为了支援我们的黑客行动特意在开始执行程序的时候将 ebp 清零了,所以第一次执行某个函数的时候压栈的 旧ebp 是 NULL。

    开始行动

    我们使用静态链接的方式编译 up.c(静态链接的可执行文件中包含所有用户态下执行的代码),然后执行它:

    [lqy@localhost temp]$ gcc -static -o up up.c
    [lqy@localhost temp]$ ./up
    0x8048464
    0x80481e1
    [lqy@localhost temp]$ 
    

    分析结果

    up 打印了了两个指向代码区的地址,接着就看它们是属于哪两个函数了:

    nm up | sort > up.txt
    
    • nm up 可列出各个全局函数的地址
    • | sort > up.txt 通过管道将 nm up 的输出作为 sort 的输入,sort 排序后输出重定向到 up.txt 文件中(输出有1910行,不得不这么做o(╯□╰)o)

    然后发现两个地址分别位于 __libc_start_main_start 中:

    ...
    08048140 T _init
    080481c0 T _start
    080481f0 t __do_global_dtors_aux
    08048260 t frame_dummy
    080482bc T main
    08048300 T __libc_start_main
    080484d0 T __libc_check_standard_fds
    ...
    

    实际上程序正好是从 _start 开始执行的,而且从 up 的反汇编结果中可看出 _start 的第一条指令xor %ebp,%ebp 就是那条传说中的将 ebp 清零的指令(两个一样的数相异或的结果一定是0)。

    那么调用 main 函数之前程序都干了些啥事呢?

    比如说堆的初始化,如果是 C++ 程序的话,全局对象的构造也是在 main 之前完成的(不能让 main 中使用全局对象的时候竟然还没构造吧!),而全局对象的析构也相当有趣地在 main 执行完了之后才执行。

    main 在你心目中的地位是不是一落千丈了?

    出差必备

    买火车票、高铁票、机票,订酒店都打9折的出行工具TRIP,点击注册

    相关文章

      网友评论

        本文标题:谁调用了main?

        本文链接:https://www.haomeiwen.com/subject/abibwhtx.html