zoukankan      html  css  js  c++  java
  • core文件无堆栈信息定位的思路

    首先需要介绍一下,阅读此文需要有基本的汇编知识。
    1、rbp(基址寄存器),rsp(堆栈寄存器),rip(指令寄存器).
    2、程序执行时,没有遇到函数调用时,IP自增长,遇到函数调用时,
    需要保存bp,ip寄存器到栈上,函数调用结束时,恢复。(这个过程的细节需要很清楚)
    (注:因此需要简单描述一下,函数调用时的步骤。
    第一,将函数执行完成后的下一条指令的地址存放进当前rsp的位置,(即结束时,ret命令利用此信息恢复rip)
    第二,进入函数后,保存当前rsp到rbp寄存器中,原因是rsp需要随时变化(结束时,需要将堆栈位置还原) )
     
    两年前,有XX专家,来讲述了一下关于无堆栈信息core文件的定位方法。
    没有留下任何文档,也没有讲述原理。
    告知了可以使用如下方法来进行排查:
    根据寄存器rbp里的地址,对临近区域的内存进行排查,查询出最近的内容为0x004xxxxx的指令,
    在gdb中用x/i 0x004xxxxx来查询为何指令(函数)。该函数可能为越界出现问题的地方,可以走查代码来排查。
    之后,我也根据此线索推导出了原理,但一直没有形成总结。今天,详细说明此中原委。
     
    软件平台:
    No LSB modules are available.
    Distributor ID:Ubuntu
    Description:Ubuntu 12.04.3 LTS
    Release:12.04
    Codename:precise
     
    简单程序如下:
    #include <iostream>
    using namespace std;
     
    void test(int n)
    {
        cout << n << endl;
        //rbp
        *(int*)(&n + 1) = 3;
        *(int*)(&n + 2) = 4;
        //rip
        *(int*)(&n + 3) = 4;
     
    }
     
    void caller()
    {
        test(20);
        cout << "caller" << endl;
    }
     
    int main()
    {
        caller();
        cout << "main" << endl;
        return 0;
    }
     
    ----------------------------------------------
    (gdb) x/32ux $rbp
    0x7fffffffe510:0xffffe520 0x00007fff 0x00400865 0x00000000
    0x7fffffffe520:0xffffe530 0x00007fff 0x0040088c 0x00000000
    0x7fffffffe530:0x00000000 0x00000000 0xf773876d 0x00007fff
     ----------------------------------------------
    (gdb) disas caller
    Dump of assembler code for function caller():
       0x0000000000400857 <+0>:push   %rbp
       0x0000000000400858 <+1>:mov    %rsp,%rbp
       0x000000000040085b <+4>:mov    $0x14,%edi
       0x0000000000400860 <+9>:callq  0x400804 <test(int)>
       0x0000000000400865 <+14>:mov    $0x4009fc,%esi
       0x000000000040086a <+19>:mov    $0x601060,%edi
       0x000000000040086f <+24>:callq  0x4006f0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
       0x0000000000400874 <+29>:mov    $0x400710,%esi
       0x0000000000400879 <+34>:mov    %rax,%rdi
       0x000000000040087c <+37>:callq  0x400700 <_ZNSolsEPFRSoS_E@plt>
       0x0000000000400881 <+42>:pop    %rbp
       0x0000000000400882 <+43>:retq 
    (gdb) disas main
    Dump of assembler code for function main():
       0x0000000000400883 <+0>: push   %rbp
       0x0000000000400884 <+1>: mov    %rsp,%rbp
       0x0000000000400887 <+4>: callq  0x400857 <caller()>
       0x000000000040088c <+9>: mov    $0x400a03,%esi
       0x0000000000400891 <+14>: mov    $0x601060,%edi
       0x0000000000400896 <+19>: callq  0x4006f0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
       0x000000000040089b <+24>: mov    $0x400710,%esi
       0x00000000004008a0 <+29>: mov    %rax,%rdi
       0x00000000004008a3 <+32>: callq  0x400700 <_ZNSolsEPFRSoS_E@plt>
       0x00000000004008a8 <+37>: mov    $0x0,%eax
       0x00000000004008ad <+42>: pop    %rbp
       0x00000000004008ae <+43>: retq
     
    根据$rbp表明,当前实际应该是执行到了 main()函数的0x000000000040088c <+9>: mov    $0x400a03,%esi的上一条指令(caller()函数)
    0x0000000000400865 <+14>:mov    $0x4009fc,%esi的上一条0x0000000000400860 <+9>:callq  0x400804 <test(int)>中。
     
    在coredump以后。
    ------------------------------------------------------
    (gdb) info register
    rax            0x7fffffffe518 140737488348440
    rbx            0x0 0
    rcx            0x7ffff77fd910 140737345739024
    rdx            0x0 0
    rsi            0x7ffff7ad1ab0 140737348704944
    rdi            0x7ffff7ad0260 140737348698720
    rbp            0x400000003 0x400000003
    rsp            0x7fffffffe520 0x7fffffffe520
    r8             0x7ffff7202740 140737339467584
    r9             0x7ffff7202740 140737339467584
    r10            0x7fffffffe280 140737488347776
    r11            0x7ffff7785c90 140737345248400
    r12            0x400720 4196128
    r13            0x7fffffffe610 140737488348688
    r14            0x0 0
    r15            0x0 0
    rip            0x4 0x4
    eflags         0x216 [ PF AF IF ]
    cs             0x33 51
    ss             0x2b 43
    ds             0x0 0
    es             0x0 0
    fs             0x0 0
    gs             0x0 0
    ------------------------------------------------------
    根据core文件的寄存器信息,可知,bp及ip均已写飞。只能利用sp指针来查询。
    ------------------------------------------------------
    (gdb) x/32ux $rsp
    0x7fffffffe520: 0xffffe530 0x00007fff 0x0040088c 0x00000000
    (gdb) x/i 0x0040088c
       0x40088c <main()+9>: mov    $0x400a03,%esi
    (gdb) disas main
    Dump of assembler code for function main():
       0x0000000000400883 <+0>: push   %rbp
       0x0000000000400884 <+1>: mov    %rsp,%rbp
       0x0000000000400887 <+4>: callq  0x400857 <caller()>
       0x000000000040088c <+9>: mov    $0x400a03,%esi
    ------------------------------------------------------
    由此,可以查出是core在了main函数中。
     
    例子使用的最简单的,实际测试时,会有多层调用,但是原理不变。
     
    限制:如果越界的长度超过了函数调用堆栈的长度,本方法则不再可用。
     
    以后补个图。今天就到这里了
     
     
  • 相关阅读:
    postman设置页面详解
    postman安装使用
    测试入门1:黑盒测试用例设计方法
    oo第十六次作业
    oo第三单元总结
    OO第二单元总结
    select语句
    MySQL数据库基础操作
    创建和查看数据库
    认识MySQL数据库
  • 原文地址:https://www.cnblogs.com/onlyforcloud/p/3446483.html
Copyright © 2011-2022 走看看