gdb 显示与代码中不同的地址

gdb showing different address than in code

我正在尝试实施缓冲区溢出攻击,我需要知道我试图溢出的缓冲区地址。

使用 GDB 显示的地址与我在代码中这样做时不同:

确切代码:

#include<stdio.h>

int main() {
   char buffer[20];
   printf("%p\n", buffer); // 0xbffff320

   return 0;
}

但是,在 gdb 中,如果我这样做:

p &buffer

我得到:0xbffff330

为什么会有差异,它会破坏我的缓冲区溢出攻击吗?

我禁用了 ALSR 和堆栈防护。

谢谢。

编辑 1:即使当我单步执行 gdb 并遇到打印行时,我也会得到 0xbffff320 作为地址

编辑 2:

环境:Ubuntu Linux 9 图像 运行 在虚拟框中 windows 7.

gdb 版本:6.8-debian

使用 GCC 编译如:gcc -g -fno-stack-protector filename.c 立即执行:./a.out 地址打印:0xbffff320

然后像这样在调试器中打开:gdb ./a.out 然后输入 b main 然后 run 然后 p &buffer

则地址为0xbffff330

编辑 3:

这是重现行为的 gdb 日志:

$ gdb ./a.out

b 主

运行

p &buffer /* 这里的地址与我 运行 可执行文件显示的地址不同 */

单步执行程序到 printf 语句 /* 此处的地址与 p &buffer 相同,但与程序 运行 时打印的内容不同 */

您系统中的数组对象存储在堆栈中。在堆栈的顶部,除其他外,还有环境。当您 运行 您的程序带有 gdb 时,gdb 将提供不同的环境(env var 及其值)来解释地址差异。

您可以通过 gdb 中的 运行ning show environment 和 shell 中的 set 命令比较输出来检查差异。

目前,我能想到的唯一原因是:

  • 您试图 print &buffer 您的程序终止后。解决方法:尝试在mainrunnext上设置断点执行printfprint &buffer.
  • 你首先 运行 你的程序在 gdb 之外,然后 运行 它在 gdb 内部但忘记执行 printfnext.
  • 您的 gdb 版本存在错误
  • 您的 gcc 版本中存在错误(gcc 可能会产生不正确的调试信息:请参阅 1 and 2

发现这是旧版本 GDB 中的预期行为(我的是 6.8-debian),如果您正确构建缓冲区溢出攻击,您可以解决此行为,这不会成为问题。

据我了解,问题是为什么 main 中的局部变量地址在程序从 shell 启动时与从 gdb 启动时不同。

这里有一个示例程序来显示差异:

mp@ubuntu:~$ cat s.c
#include<stdio.h>

int main(int argc, char **argv) {
  char buffer[20];
  system("env");
  printf("%s %p\n", argv[0], buffer);

  return 0;
}

我们会运行它在干净的环境中。 (我也禁用了 ASLR)。

mp@ubuntu:~$ env -i sh
$ ./s
PWD=/home/mp
./s 0xbffffe48

$ gdb ./s
(gdb) run
Starting program: /home/mp/s 
COLUMNS=80
PWD=/home/mp
LINES=42
/home/mp/s 0xbffffe08

gdb 的 print &buffer 命令的输出与程序的地址概念相同,但它们与程序在 运行 中的 shell 时不同。

(gdb) b 6
Breakpoint 1 at 0x804849c: file s.c, line 6.
(gdb) run
Starting program: /home/mp/s 
COLUMNS=80
PWD=/home/mp
LINES=42

Breakpoint 1, main (argc=1, argv=0xbffffed4) at s.c:6
6      printf("%s %p\n", argv[0], buffer);
(gdb) p &buffer
 = (char (*)[20]) 0xbffffe08
(gdb) n
/home/mp/s 0xbffffe08
8      return 0;

造成差异的原因有以下几点:

  • gdb 正在调用带有绝对路径名的程序,因此 argv 数组更大。
  • gdb 设置(或在本例中添加)两个环境变量。这是在 readline/shell.c:sh_set_lines_and_columns() 中完成的。所以环境数组更大。

要从环境中删除这两个变量,您可以使用 unset environment, or set exec-wrapper 到 运行 env -u ...。这样,程序在 gdb 下的地址与 shell 中的 运行 相同(如果我们使用绝对路径名)。

$ `pwd`/s
PWD=/home/mp
/home/mp/s 0xbffffe28

$ gdb `pwd`/s
(gdb) set exec-wrapper env -u LINES -u COLUMNS
(gdb) run
Starting program: /home/mp/s 
PWD=/home/mp
/home/mp/s 0xbffffe28