如何预测实际执行和 gdb 控制执行之间的地址空间布局差异?

逆向工程 数据库 记忆
2021-06-28 02:27:33

这是困扰我很久的事情。我可以观察到程序的实际执行与gdb受控程序的执行之间存在差异

但是,这里有一个例子:

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

    #include <stdio.h>
    #include <stdlib.h>
    
    int main ()
    {
      char c = 0;
    
      printf ("Stack address: %p\n", &c);
    
      return EXIT_SUCCESS;
    }
    
  2. 然后,我们禁用 ASLR(我们使用进程的个性标志,而不是通过系统范围的方法/proc/sys/kernel/randomize_va_space):

    $> setarch `uname -m` -R /bin/bash
    
  3. 然后,在真实的内存环境中运行:

    Stack address: 0x7fffffffe1df
    
  4. 并且,同样通过gdb

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

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

而且,这种差异从何而来/从何而来?

2个回答

可能还涉及其他因素,但我的猜测是存储在堆栈中的流程环境变量的变化是导致此问题的原因。

运行一个只打印出环境变量的小程序,在我的系统上在 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 附加到它,这应该避免环境变量中的这些变化(假设这实际上是导致您问题的原因)。

如果您的流程是短暂的,则很难在流程退出之前暂停该流程。也许其他人对在暂停状态下启动进程有一些好的建议;我通常使用第二个程序像这样一个追赶的过程,因为它是启动和暂停,所以我可以在调试器附加到它。

只是为了补充答案,我可以告诉如何接近干净的环境,尽管gdb. 事实上,有两种方法可以达到这个目的:

  1. 我们可以删除添加的额外环境变量gdb,如下所示:

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

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

  2. 还可以生成易受攻击程序的内存核心并使用以下命令对其进行分析gdb

    $> gdb vuln_program core
    

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

这是您可以gdb用来跟踪程序的两种方法,与实际执行没有太大区别。但是,他们还有很多!