【发布时间】: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