【问题标题】:Why this piece of code can get environment variable address?为什么这段代码可以获取环境变量地址?
【发布时间】:2016-11-08 14:14:14
【问题描述】:

64-bit Linux stack smashing tutorial: Part 1 使用Get environment variable address gist 获取环境变量地址。前提是先通过echo 0 > /proc/sys/kernel/randomize_va_space禁用ASLR。

要点的内容是:

/*
 * I'm not the author of this code, and I'm not sure who is.
 * There are several variants floating around on the Internet, 
 * but this is the one I use. 
 */

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

int main(int argc, char *argv[]) {
    char *ptr;

    if(argc < 3) {
        printf("Usage: %s <environment variable> <target program name>\n", argv[0]);
        exit(0);
    }
    ptr = getenv(argv[1]); /* get env var location */
    ptr += (strlen(argv[0]) - strlen(argv[2]))*2; /* adjust for program name */
    printf("%s will be at %p\n", argv[1], ptr);
}

为什么*2用来调整程序名?

我的猜测是程序名在堆栈上方保存了两次。

https://lwn.net/Articles/631631/ 的下图给出了更多细节:

------------------------------------------------------------- 0x7fff6c845000
 0x7fff6c844ff8: 0x0000000000000000
        _  4fec: './stackdump\0'                      <------+
  env  /   4fe2: 'ENVVAR2=2\0'                               |    <----+
       \_  4fd8: 'ENVVAR1=1\0'                               |   <---+ |
       /   4fd4: 'two\0'                                     |       | |     <----+
 args |    4fd0: 'one\0'                                     |       | |    <---+ |
       \_  4fcb: 'zero\0'                                    |       | |   <--+ | |
           3020: random gap padded to 16B boundary           |       | |      | | |

在此图中,./stackdump 用于执行程序。所以我可以看到程序名称./stackdump 保存在环境字符串上方一次。如果./stackdump 是从 Bash shell 启动的,Bashell 会将其保存在带有密钥 _ 的环境字符串中:

_

(下划线。)在 shell 启动时,设置为用于调用正在执行的 shell 或 shell 脚本的绝对路径名,如在 环境或参数列表。随后,展开到最后 扩展后的前一个命令的参数。也设置为 用于调用每个执行的命令并放置在 导出到该命令的环境。检查邮件时,这 参数保存邮件文件的名称。

环境字符串在堆栈之上。所以程序名会在堆栈上方再次保存。

【问题讨论】:

  • 你到底在问什么?该代码有效,因为 getenv 获取环境变量的地址,并且对程序的调用也占用了堆栈上的空间,因此您相应地调整指针。它在代码的 cmets 中。
  • 据我所知,在堆栈上分配的程序名称中,每个字符通常大约有 2 个字节。我第一次看到这段代码是在 Jon Erickson 的 Hacking: The Art of Exploitation 中。我建议在那里阅读更多内容,或者研究 linux 内核以了解堆栈在内存中的外观。
  • @JacobH 是的,代码来自 Jon Erickson 的 Hacking: The Art of Exploitation, 2nd Edition 的第 147 和 148 页。但是这本书并没有解释它为什么起作用。
  • 这基本上是因为程序名被存储了两次,一次在堆栈的最顶部,一次作为argv[0]。 (当然,argv[0] 可能不是程序名称,这取决于程序是如何被调用的,这就是为什么程序名称需要单独放在堆栈上的原因。)例如,参见lwn.net/Articles/631631

标签: c linux getenv


【解决方案1】:

如果有人仍然想知道为什么。这是因为程序名除了在所有环境变量之前被压入堆栈之外,还存储在环境变量名“_”中。

您可以通过将 gdb 附加到进程并检查最后一个环境变量下方的堆栈内容来检查这一点。假设 0x7fffffffabcd 是最后一个环境变量的地址:

$ gdb -p <pid>

(gdb) x/20s 0x7fffffffabcd

argv[0] 中存储的程序名称不会影响环境变量的地址,因为它位于堆栈中最后一个环境变量的顶部。

【讨论】:

    【解决方案2】:

    将以下代码另存为stackdump.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/auxv.h>
    
    int main(int argc, char *argv[]) {
      char *ptr;
      int i;
    
      for (i = 0; i < argc; i++) {
        printf("  argv[%d]: %p, %p, %s\n", i, argv + i, argv[i], argv[i]);
      }
    
      char * program = (char *)getauxval(AT_EXECFN);
      printf("AT_EXECFN:               , %p, %s\n", program, program);
      char* path = getenv("PATH");
      printf("     PATH:               , %p, %s\n", path, path);
      char* underscore = getenv("_");
      printf("        _:               , %p, %s\n", underscore, underscore);
    }
    

    首先,运行gcc -o stackdump stackdump.c 编译代码。其次,执行echo 0 &gt; proc/sys/kernel/randomize_va_space。三、运行./stackdump zero one two给:

      argv[0]: 0x7fffffffe4a8, 0x7fffffffe6e5, ./stackdump
      argv[1]: 0x7fffffffe4b0, 0x7fffffffe6f1, zero
      argv[2]: 0x7fffffffe4b8, 0x7fffffffe6f6, one
      argv[3]: 0x7fffffffe4c0, 0x7fffffffe6fa, two
    AT_EXECFN:               , 0x7fffffffefec, ./stackdump
         PATH:               , 0x7fffffffee89, /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/cloud-user/.local/bin:/home/cloud-user/bin
            _:               , 0x7fffffffefe0, ./stackdump
    

    ./stackdump 的三个副本位于程序的地址空间中,如上所示。其中两个具有比 PATH 更高的地址,如下所示:

    AT_EXECFN: 0x7fffffffefec, ./stackdump
            _: 0x7fffffffefe0, ./stackdump
         PATH: 0x7fffffffee89, /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/cloud-user/.local/bin:/home/cloud-user/bin
    

    所以*2的原因是_环境变量和AT_EXECFNauxiliary vector value

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-22
      • 1970-01-01
      • 1970-01-01
      • 2010-09-23
      • 1970-01-01
      • 2015-08-10
      • 2021-08-06
      相关资源
      最近更新 更多