zoukankan      html  css  js  c++  java
  • gdb分析堆栈破坏实例

    gdb分析堆栈破坏实例

    原文链接:https://blog.csdn.net/mergerly/article/details/80523750


    一、定位bug性质和范围
    1、带符号分析dump

    $ gdb IMActivityServer.symbol core.32530
    (gdb) bt

    看不出任何信息,日志也看不出什么,怀疑是堆栈破坏

    2、增加堆栈保护, 用编译参数-fstack-protector-all为所有函数插入保护代码,编译版本,再次带符号查看崩溃dump

    $ gdb IMActivityServer.symbol core.32530
    (gdb) bt

    堆栈可以看出函数名了cmdMsgParse,查看源码文件ActivityServer.cpp:930是函数返回地址,断定是某一个消息引起的堆栈破坏,这个是统一消息处理函数,消息量很大,

    3、增加消息号处理日志,再放一个版本
    多台服务器的日志最后一行都是:

    180531-12:43:51 ActivityServer[17701] ERROR: [ActivityInfoManager.cpp:1293] cmd(51) param(0) len(70) server(0) id(0)
    基本可以判断是51号消息引起的

    二、详细分析bug
    51号消息是一个通用转发包装消息,需要解析内部消息内容,考虑下断点统一处理函数
    ActivityInfoManager::msgParseTask

    1、先找到函数定义,看是否正确,有源码可以省略

    2、再断下来解析参数

    3、根据参数值下条件断点

    // 清除老断点
    (gdb) clear
    Deleted breakpoint 1
    // 下条件断点
    (gdb) break ActivityInfoManager.cpp:1293 if ptNullCmd->cmd == 51
    Breakpoint 2 at 0x6bdd50: file ActivityInfoManager.cpp, line 1293.
    (gdb) c
    Continuing.

    4、分析51号消息

    // 查看断下来的消息
    (gdb) p *(const Cmd::t_NullCmd *) 0x7f83877fdc30

    $11 = {{{byCmd = 51 '3', byParam = 0 '00'}, {cmd = 51 '3', para = 0 '00'}}}

    // 51号消息结构等价于
    struct stActivityInCmd{
    BYTE cmd;
    BYTE para;
    DWORD ActId;
    WORD size;
    char data[0]
    }
    // 消息在内部data中,可以知道data是stActivityInCmd结构体地址+8字节,头也是Cmd::t_NullCmd结构体
    (gdb) p *(const Cmd::t_NullCmd *) 0x7f83877fdc30+8
    $11 = {{{byCmd = 51 '3', byParam = 12 'f'}, {cmd = 51 '3', para = 12 'f'}}}
    // 可以看出是51号消息,子消息号是12,查源码知道消息是'Cmd::Activity::stOpMount'
    // 显示详细结构内容
    (gdb) p *(Cmd::Activity::stOpMount*)0x7f83877fdc38
    $10 = {<Cmd::t_NullCmd> = {{{byCmd = 51 '3', byParam = 12 'f'}, {cmd = 51 '3', para = 12 'f'}}}, dwReqFunction = 10,
    szName = "领工资00sigin_pay_map_.size:[%d]00", byOpType = 1 '01', dwIndex = 0, dwUserId = 22684283, wAddType = 32,
    dwTimeStart = 1527740441, dwTimeEnd = 1528345241, bNeedDelMount = false, wDelType = 0, bExtension = true}
    查看消息Cmd::Activity::stOpMount的处理流程,发现一处堆栈覆盖问题

    Cmd::Activity::stActivityInCmd cmd;
    ...
    bcopy(rev->data, cmd.data, rev->size);
    消息没有初始化就使用了,直接往data里面写数据,参考上面的结构体定义,data指向的是结构体堆栈末尾,导致数据直接写入了堆栈中,覆盖了原有堆栈内容。

    三、修复bug
    修复的方法很简单,初始化一下结构体再使用就可以了。

    四、gdb打印日志

    $ gdb attach 28644
    // 加载符号
    (gdb) symbol-file IMActivityServer.symbol
    Reading symbols from /home/ztgame/IMTESTVERSION/release/IMActivityServer.symbol...done.
    // 开启日志
    (gdb) set logging on
    Future logs will be written to gdb.txt.
    Copying output to gdb.txt.
    // 下断点
    (gdb) break ActivityInfoManager.cpp:1290
    Breakpoint 2 at 0x6b70f0: file ActivityInfoManager.cpp, line 1290.
    // 导入python库
    (gdb) python import datetime
    // 增加断点脚本命令
    (gdb) commands 2 //指令集设置命令,断点序号
    Type commands for breakpoint(s) 2, one per line.
    End with a line saying just "end".
    >silent //断点触发时不打印断点信息
    >python gdb.execute("set $now="" + datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + """)
    >printf "%s cmd(%u) param(%u) len(%u) srvtype(%u) srvid(%u) ",$now,ptNullCmd->cmd, ptNullCmd->para,cmdLen,((Cmd::Activity::stServerParam*)server_param)->type,((Cmd::Activity::stServerParam*)server_param)->serverid
    >continue
    >end //指令集设置结束时必须用end结束
    (gdb) c
    打开gdb.txt

  • 相关阅读:
    C++基础知识(二)
    C++基础知识(一)
    RT-thread 设备驱动组件之IIC总线设备
    RT-thread 设备驱动组件之SPI设备
    RT thread 设备驱动组件之USART设备
    RT-thread 设备驱动组件之PIN设备
    RT-thread finsh组件工作流程
    C语言知识点
    RT-thread main函数分析
    堆和栈的区别
  • 原文地址:https://www.cnblogs.com/cqx6388/p/14479434.html
Copyright © 2011-2022 走看看