1

64位Linux栈粉碎教程:第1部分使用Get environment variable address gist获取环境变量地址。先决条件是首先通过echo 0 > /proc/sys/kernel/randomize_va_space.

要点的内容是:

/*
 * 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 会将其保存在带有 key 的环境字符串中_

_

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

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

4

2 回答 2

1

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

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

$ gdb -p <pid>

(gdb) x/20s 0x7fffffffabcd

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

于 2017-11-03T11:00:09.400 回答
0

将以下代码另存为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 > 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_EXECFN 辅助向量值

于 2017-11-07T14:21:58.410 回答