很长一段时间困扰我。我可以观察到,程序的实际执行与gdb控制的程序之间是有区别的。

,但这是一个示例:



首先,这是示例代码(我们使用自动变量获取堆栈的位置):

#include <stdio.h>
#include <stdlib.h>

int main ()
{
  char c = 0;

  printf ("Stack address: %p\n", &c);

  return EXIT_SUCCESS;
}



然后,我们禁用ASLR(我们使用进程的个性标志,而不是通过/proc/sys/kernel/randomize_va_space使用系统范围的方法):

$> setarch `uname -m` -R /bin/bash



然后,运行真实的内存环境:

Stack address: 0x7fffffffe1df



通过gdb相同:

 (gdb) r
 Starting program: ./gdb-against-reality
 Stack address: 0x7fffffffe17f
 [Inferior 1 (process 5374) exited normally]
 (gdb) 



所以,这两次运行之间有96个字节的差异。但是,如何在不让其在实际内存布局中运行的情况下(仅通过了解gdb内存布局)如何预测给定程序的这种差异?

以及,从何而来区别?

#1 楼

可能还涉及其他因素,但我猜想是存储在堆栈中的过程环境变量中的更改是导致此问题的原因。
运行一个仅打印出在我的系统上在gdb内外运行时,环境变量揭示了环境变量的几种变化。

int main(int argc, char **argv, char** envp)
{
  char** env;
  for (env = envp; *env != 0; env++)
  {
    char* thisEnv = *env;
    printf("%s\n", thisEnv);    
  }
}


首先,在gdb下运行时,有一个LINES变量在gdb外部启动该进程时不存在:

LINES=83


其次,下划线环境变量不同。在gdb外部运行时,它被设置为可执行文件的名称:

_=./gdbtest


但是从gdb内部启动时,它被设置为gdb二进制文件的路径:

_=/usr/bin/gdb


您可以尝试正常运行该程序,然后使用gdb / gdbserver附加该程序,这应避免环境变量出现这些变化(假设实际上是什么导致了您的问题)。

如果您的进程是短暂的,那么在退出之前可能很难暂停该进程。也许其他人对于在暂停状态下启动流程提出了一些好的建议;我通常使用第二个这样的程序来捕获启动过程并暂停它,以便可以将调试器附加到该程序。

评论


关于stackoverflow的答案显示了如何在受控环境stackoverflow.com/a/17775966上运行gdb。您可以简单地使用他的脚本(记住要在gdb中运行未设置的命令)

–维塔利·奥西波夫(Vitaly Osipov)
2014-02-16 8:03



#2 楼

只是为了补充答案,我可以告诉我尽管gdb仍如何接近清洁的环境。实际上,有两种方法可以解决此问题:




我们可以摆脱gdb添加的额外环境变量,如下所示:

(gdb) unset environment LINES
(gdb) unset environment COLUMNS


在运行程序之前,请编写这些命令,并且您应该靠近正常环境。请注意,您仍然必须注意_变量。


还可以生成易受攻击程序的内存核心,并使用gdb对其进行分析:

$> gdb vuln_program core


您应该只看内存,而不要看runnextstep,因为这样做会迫使您用新的内存(带移位)重新启动程序。 >

这是可以与gdb一起使用的两种方法来跟踪程序,与实际执行没有太大差异。但是,还有很多其他人!