基础的缓冲区溢出实践通常需要确定运行状态下程序中的某些局部变量的地址,如需要确定输入缓冲区的起始地址从而获得注入缓冲区中的机器指令的起始地址等。在 Linux 环境下,可通过 gdb 对程序进行动态调试,从而获得程序运行状态下的信息( 关闭 ALSR 机制 ),基础的 gdb 操作可参见笔者的文章Linux下编辑、编译、调试命令总结——gcc和gdb描述。使用 gdb 可以方便的获取程序动态运行状态下的信息,但通过 gdb 动态调试获取的诸如缓冲区的起始地址等信息可能与程序实际运行时的信息并不相同,从而影响缓冲区溢出实践的效果。

问题描述

  通过 gdb 运行的程序的内存布局较之程序单独运行时的内存布局可能略有不同.通过以下实例程序进行简单的验证。

  #include<stdio.h>

  int main(int argc , char *argv[] , char *envp[])
  {
      char buff[8];
      printf("address of buff : %p \n", buff );
    
      return 0;
  }

  关闭 ALSR 机制后,通过 gcc -m32 -o hello -g -fno-stack-protector hello.c 编译生成可执行文件 hello。直接运行可执行程序,获得缓冲区的起始地址为 0xffffcfa8.

  

  使用 gdb 对 hello 文件动态调试,获得缓冲区的起始地址为 0xffffcf88.可以看到两者地址之间存在32个字节的差距。   

  

  正常程序运行时,会将环境变量字符串数组和命令行参数字符串数组存放在栈顶,而程序使用的局部变量等数据则位于这些字符串数组之后。环境变量字符串数组记录了诸如当前用户名、终端类型、搜索路径等环境信息。程序直接运行时,程序进程继承的是运行其的 shell 的环境变量,而程序通过 gdb 运行时,程序进程继承的是 gdb 的环境变量,这两者存在不同,从而会造成位于栈上的局部变量的地址发生改变。用户可在 gdb 中运行 show environment 命令获得环境变量参数。

    show environment    //在 gdb 中获得当前程序运行的环境变量

  

  较之程序直接运行,位于栈顶的环境变量主要有以下变化:

  (1) _ 环境变量的内容发生改变,在程序直接运行时,_ 变量存放的是程序的执行路径,而通过 gdb 运行程序时,_ 变量存放的是 gdb 的执行路径。

  使用 gdb 运行程序时,_ 环境变量的值为 /usr/bin/gdb.而在程序直接运行时,_ 环境变量的值应为程序的执行路径,如./hello.

  

  (2) 通过 gdb 运行的调试程序继承了 gdb 的环境变量,其中包含新加入的环境变量 LINES 和 COLUMNS

  

  (3) 位于栈上的参数列表也可能不同,当用户通过 ./hello 直接在shell 中运行程序时,位于参数数组的第一项 argv[0] 内容为"./hello" ,而用户通过 gdb 运行 hello 程序时,程序的参数列表的第一项 argv[0] 的值为该程序的绝对路径"/home/yh/hello",这也会造成程序运行时局部变量地址的差异。建议终端环境下使用绝对路径运行程序,避免该差异。

  

功能支持

  为了解决上述由于环境变量不同所产生的程序局部变量地址的差异,需要在使用 gdb 运行程序之前进行一定的操作,gdb 为用户调试提供了以下功能支持。

  (1) gdb 提供命令对传递给调试进程的环境变量进行操作和修改。

    show paths                //显示可执行文件的搜索路径(即为PATH变量的内容)
show environment [ varname ] //显示启动调试程序时 gdb 传递给它的环境变量,不指定具体的变量名时,则会显示所有的环境变量,可使用 env 作为 environment 的简写
set environment varname [= value] //设置传递给调试程序的环境变量varname的值为value,不指定value时,值默认为NULL
unset environment varname //设置不会被传递给调试程序的环境变量

  用户可以通过 unset env LINES 和 unset env COLUMNS 命令使得调试程序的栈上不会新增额外的环境变量 LINES 和 COLUMNS。

  (2) Linux 平台提供了标准 wrapper 程序 env 对最终传递给程序的环境变量进行设置。env 的详细用法可通过 man env 进行查看,其简单的参数如下。

    env [options] [-] [ name=value ] [command [args] ...]  
  //通过 command 指定由 env 启动的程序,不指定 command 时,会将当前 env 指定的环境输出,如直接运行 env ,输出的为当前的所有环境变量
options:
-i //忽略环境变量,即不传递环境变量给程序
-u varname //忽略 varname 指定的环境变量,即不将其传递给程序
- //作用与 -i 相同

  (3) gdb 可通过 wrapper 函数运行调试程序。当设置好 wrapper 程序后,gdb 会以 exec wrapper hello 的 shell 命令的形式启动调试程序 Hello,wrapper程序首先运行并最终启动调试进程,之后由 gdb 对调试进程进行控制。通过 wrapper 程序,即可控制传递给调试进程的环境变量。

    set exec-wrapper wrapper  //设置 wrapper 程序为 wrapper
show exec-wrapper    //显示当前的 wrapper 程序
unset exec-wrapper     //取消对 wrapper 程序的设置

  可以使用标准的 wrapper 程序 env 对传递给调试进程的环境变量进行控制。

解决方案

  借助上述功能,可以通过以下方案解决 gdb 运行调试程序时局部变量地址变化的问题。

  A.不传递环境变量数组给调试程序。

  (1)通过 env 运行 gdb ,并将传递给 gdb 的环境变量设置为空。此时 gdb 环境下所包含的环境变量仅为其新增加的 LINES 和 COLUMNS。

    env - gdb /home/yh/hello    //设置传递给 gdb 的环境变量为空,注意使用待调试程序的完整路径名

  此时,通过 show env 显示的 gdb 中环境变量的列表如下

      

  (2)通过 gdb 对环境变量的设置命令 unset env ,设置不将上述两个环境变量传递给调试程序,使得最终运行调试程序时,不会有环境变量被调试程序继承。

    unset env LINES
unset env COLUMNS

  经过以上两步,通过 gdb 运行的调试程序 hello 的局部变量的地址与通过 env - /home/yh/hello 运行的 hello 程序的地址是一致的(两者的进程栈上均不包含环境变量数组,且 argv[0] 均为绝对路径地址)。

  当待调试的程序需要使用某些环境变量的值时,只需通过 env 程序指定所需的环境变量即可,而不引入不相同的环境变量如 _ ,或者直接通过 env 的 -u 选项去除引入差异的环境变量,而保留其它的环境变量。

  

  B.基于同样的原理,可以正常启动 gdb ,但对 wrapper 程序进行设置。

   gdb hello          //正常启动 gdb
set exec-wrapper env -u COLUMNS -u LINES -u _ //在 gdb 中设置 wrapper 程序
r   //开始调试,借助设置的 wrapper 程序的功能,hello程序不会继承 gdb 中特定的引入差异的环境变量 env -u _ /home/yh/sc/hello //通过该命令直接运行程序,注意使用绝对路径

  此时通过 gdb 运行程序时调试程序不会继承 gdb 引入的不同的环境变量,这样获得的程序局部变量的地址与通过 env -u _ /home/yh/hello 的方式启动的 hello 程序的局部变量地址相同。

参考资料

  1.Debugging with GDB:Environment

  2.Debugging with GDB:  Starting

  3.Buffer overflow works in gdb but not without it- Stack Overflow

  4.How to predict address space layout differences between real and gdb-controlled executions? - StackExchange

针对 Linux 环境下 gdb 动态调试获取的局部变量地址与直接运行程序时不一致问题的解决方案的更多相关文章

  1. 嵌入式arm linux环境中gdb+gdbserver调试

    一.前言嵌入式Linux系统中,应用开发过程中,很多情况下,用户需要对一个应用程序进行反复调试,特别是复杂的程序.采用GDB方法调试,由于嵌入式系统资源有限性,一般不能直接在目标系统上进行调试,通常采 ...

  2. linux环境下,双击直连ping私有地址时候出现Destination host unreachable 解决办法

    在确保网线无故障的情况下,采取以下步骤 1.查看本机的hostname vim    /etc/sysconfig/network 2.编辑/etc/hosts vim /etc/hosts 加入以下 ...

  3. Linux环境下段错误的产生原因及调试方法小结(转)

    最近在Linux环境下做C语言项目,由于是在一个原有项目基础之上进行二次开发,而且 项目工程庞大复杂,出现了不少问题,其中遇到最多.花费时间最长的问题就是著名的“段错误”(Segmentation F ...

  4. Linux环境下段错误的产生原因及调试方法小结

    转载自http://www.cnblogs.com/panfeng412/archive/2011/11/06/2237857.html 最近在Linux环境下做C语言项目,由于是在一个原有项目基础之 ...

  5. 【转】【调试技巧】Linux环境下段错误的产生原因及调试方法小结

    本文转自:http://www.cnblogs.com/panfeng412/archive/2011/11/06/segmentation-fault-in-linux.html 1. 段错误是什么 ...

  6. Linux环境下段错误的产生原因及调试方法小结【转】

    转自:http://www.cnblogs.com/panfeng412/archive/2011/11/06/2237857.html 最近在Linux环境下做C语言项目,由于是在一个原有项目基础之 ...

  7. 转:Linux环境下段错误的产生原因及调试方法小结

    源地址:http://www.cnblogs.com/panfeng412/archive/2011/11/06/2237857.html 补充:http://baike.baidu.com/link ...

  8. 交叉编译问题记录-嵌入式环境下 GDB 的使用方法

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10693247.html 本文以嵌入式 Linux 环境下的 gdb 使用为例,记录交叉编 ...

  9. PHP 命令行模式实战之cli+mysql 模拟队列批量发送邮件(在Linux环境下PHP 异步执行脚本发送事件通知消息实际案例)

    源码地址:https://github.com/Tinywan/PHP_Experience 测试环境配置: 环境:Windows 7系统 .PHP7.0.Apache服务器 PHP框架:ThinkP ...

随机推荐

  1. api.setFrameGroupIndex

    设置 frame 组当前可见 frame setFrameGroupIndex({params}) params name: 类型:字符串 默认值:无 描述:frame 组名字 index: 类型:数 ...

  2. 使用 RetroShare 分享资源

    本文告诉大家如何使用 RetroShare 来分享资源.因为 RetroShare 是一个 p2p 分享的工具,所以他比现在很多云盘都好用,在网上,很多大神说可以用来代替电驴.之所以推荐这个软件,因为 ...

  3. .net core 2.2 部署CentOS7(5)部署.net core mvc

    目录: .net core 2.2 部署CentOS7(1)安装虚拟机 .net core 2.2 部署CentOS7(2)给虚拟机安装CentOS7 .net core 2.2 部署CentOS7( ...

  4. 基于Udp的五子棋对战游戏

    引言 本文主要讲述在局域网内,使用c#基于Udp协议编写一个对战的五子棋游戏.主要从Udp的使用.游戏的绘制.对战的逻辑这三个部分来讲解. 开发环境:vs2013,.Net4.0,在文章的末尾提供源代 ...

  5. Ubuntu下彻底卸载wine

    简介: wine是linux下模拟windows的一个东西,可以用来安装exe程序,但是对于wine的卸载确 实非常麻烦的,这里是彻底卸载wine的一个教程. ##首先卸载wine sudo apt- ...

  6. 自定义RatingBar评分控件

    1.介绍 实现类似美团外卖评分供能,系统提供了RatingBar,今天来自定义一波,当做自定义view的一个学习,效果如下,能够滑动或者点击变化星星数量 2.自定义属性 在values目录下的attr ...

  7. Android应用程序启动过程(二)分析

    本文依据Android6.0源码,从点击Launcher图标,直至解析到MainActivity#OnCreate()被调用. Launcher简析 Launcher也是个应用程序,不过是个特殊的应用 ...

  8. hive 排序 order by sort by distribute by cluster by

    order by:     order by是全局排序,受hive.mapred.mode的影响.       使用orderby有一些限制:     1.在严格模式下(hive.mapred.mod ...

  9. Storm监控文件夹变化 统计文件单词数量

    监控指定文件夹,读取文件(新文件动态读取)里的内容,统计单词的数量. FileSpout.java,监控文件夹,读取新文件内容 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ...

  10. 外业数据采集平台(GPS+Android Studio+Arcgis for android 100.2.1)

    外业数据采集平台 1. 综述 在室外,通过平板或者手机接收GPS坐标,实时绘制点.线.面数据,以便为后续进行海域监测.土地确权.地图绘图提供有效数据和依据. 2. 技术路线 Android studi ...