C 为什么这段代码可以获取环境变量地址?
用于获取环境变量地址。先决条件是首先通过C 为什么这段代码可以获取环境变量地址?,c,linux,getenv,C,Linux,Getenv,用于获取环境变量地址。先决条件是首先通过echo 0>/proc/sys/kernel/randomize\u va\u 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. */ #incl
echo 0>/proc/sys/kernel/randomize\u va\u 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);
}
在此图中,/stackdump
用于执行程序。因此,我可以看到程序名/stackdump
在环境字符串上方保存一次。如果从bashshell启动了/stackdump
,则Bashell将使用键\uu
将其保存在环境字符串中:
_
(下划线。)在shell启动时,设置为绝对路径名,用于调用在中传递的shell或正在执行的shell脚本
环境或参数列表。随后,扩展到最后一个
展开后上一个命令的参数。也设置为
用于调用已执行并放置在中的每个命令的完整路径名
环境导出到该命令。在检查邮件时,此
参数保存邮件文件的名称
环境字符串位于堆栈上方。因此,程序名会在堆栈上方另存一次。以防有人仍在想为什么。这是因为程序名也存储在一个环境变量名“\u1”中,而不是在所有环境变量之前被推送到堆栈上 您可以通过将gdb附加到进程并检查最后一个环境变量下面的堆栈内容来检查这一点。假设0x7FFFFFABCD是最后一个环境变量的地址:
$ gdb -p <pid>
(gdb) x/20s 0x7fffffffabcd
$gdb-p
(gdb)x/20s 0x7fffffffabcd
存储在
argv[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);
}
如上所示,程序的地址空间中有三份/stackdump
。其中两个具有比路径更高的地址,如下所示:
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
的原因是\u
环境变量和AT\u EXECFN
您到底在问什么?代码之所以有效,是因为getenv获取环境变量的地址,而对程序的调用也会占用堆栈上的空间,因此需要相应地调整指针。据我所知,在堆栈上分配的程序名中,每个字符通常有2个字节。我看到这段代码的第一个地方是在黑客中:Jon Erickson的剥削艺术。我建议在那里多读一些,或者研究一下linux内核,以了解堆栈在内存中的外观。@JacobH是的,代码源于Jon Erickson的第二版《黑客:利用的艺术》第147页和第148页。但这本书并没有解释它为什么会工作,基本上是因为程序名存储了两次,一次在堆栈的最顶端,另一次作为argv[0]。(当然,argv[0]可能不是程序名,这取决于调用程序的方式,这就是为什么程序名需要单独位于堆栈上的原因。)例如,请参阅,
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
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