为啥堆栈上的LD_PRELOAD的值
Posted
技术标签:
【中文标题】为啥堆栈上的LD_PRELOAD的值【英文标题】:why is the value of LD_PRELOAD on the stack为什么堆栈上的LD_PRELOAD的值 【发布时间】:2013-04-13 20:02:44 【问题描述】:我正在研究缓冲区溢出并解决一些兵棋推演。 有一个问题,缓冲区上方的所有堆栈内存都设置为0,除了main的返回地址,它将是:
buffer
[0000000...][RET][000000...]
我可以覆盖那个 RET。 所以我找到了一些解决这个问题的提示。 这是使用 LD_PRELOAD。 有人说 LD_PRELOAD 的值不仅在堆栈的环境变量区域中,而且在堆栈的某个地方。 所以我设置了 LD_PRELOAD 并搜索它并使用 gdb 找到它。
$ export LD_PRELOAD=/home/coffee/test.so
$ gdb -q abcde
(gdb) b main
Breakpoint 1 at 0x8048476
(gdb) r
Starting program: /home/coffee/abcde
Breakpoint 1, 0x8048476 in main ()
(gdb) x/s 0xbffff6df
0xbffff6df: "@èC\001@/home/coffee/test.so"
(gdb) x/s 0xbffffc59
0xbffffc59: "LD_PRELOAD=/home/coffee/test.so"
(gdb) q
The program is running. Exit anyway? (y or n) y
$
原来如此! 现在我知道 LD_PRELOAD 的值在缓冲区下面的堆栈上,现在我可以利用了!
但我想知道为什么 LD_PRELOAD 会加载到该内存地址上。 该值也在堆栈的环境变量区域!
这样做的目的是什么? 谢谢。
【问题讨论】:
环境由execve(2)
系统调用放入堆栈,根据ABI规范
@Basile Starynkevitch 我的意思是 LD_PRELOAD 放在两个地方。
@lbyeoksan 我敢肯定 Basile Starynkevitch 知道他在说什么。
我想你会找到argv[argc+1] == environ
,所以完整的环境在堆栈上,如果设置了LD_PRELOAD
,则包括LD_PRELOAD
。
@Jonathan Leffler 嗯。我不明白。我认为 argv[argc+1] 在我的问题中有点 0xbffffc59 。那么0xbffff6df呢?
【参考方案1】:
探索堆栈布局的代码:
#include <inttypes.h>
#include <stdio.h>
// POSIX 2008 declares environ in <unistd.h> (Mac OS X doesn't)
extern char **environ;
static void dump_list(const char *tag, char **list)
char **ptr = list;
while (*ptr)
printf("%s[%d] 0x%.16" PRIXPTR ": %s\n",
tag, (ptr - list), (uintptr_t)*ptr, *ptr);
ptr++;
printf("%s[%d] 0x%.16" PRIXPTR "\n",
tag, (ptr - list), (uintptr_t)*ptr);
int main(int argc, char **argv, char **envp)
printf("%d\n", argc);
printf("argv 0x%.16" PRIXPTR "\n", (uintptr_t)argv);
printf("argv[argc+1] 0x%.16" PRIXPTR "\n", (uintptr_t)(argv+argc+1));
printf("envp 0x%.16" PRIXPTR "\n", (uintptr_t)envp);
printf("environ 0x%.16" PRIXPTR "\n", (uintptr_t)environ);
dump_list("argv", argv);
dump_list("envp", envp);
return(0);
程序编译为x
,我在经过消毒的环境下运行它:
$ env -i HOME=$HOME PATH=$HOME/bin:/bin:/usr/bin LANG=$LANG TERM=$TERM ./x a bb ccc
4
argv 0x00007FFF62074EC0
argv[argc+1] 0x00007FFF62074EE8
envp 0x00007FFF62074EE8
environ 0x00007FFF62074EE8
argv[0] 0x00007FFF62074F38: ./x
argv[1] 0x00007FFF62074F3C: a
argv[2] 0x00007FFF62074F3E: bb
argv[3] 0x00007FFF62074F41: ccc
argv[4] 0x0000000000000000
envp[0] 0x00007FFF62074F45: HOME=/Users/jleffler
envp[1] 0x00007FFF62074F5A: PATH=/Users/jleffler/bin:/bin:/usr/bin
envp[2] 0x00007FFF62074F81: LANG=en_US.UTF-8
envp[3] 0x00007FFF62074F92: TERM=xterm-color
envp[4] 0x0000000000000000
$
如果你仔细研究的话,你会发现main()
的argv
参数是一系列指向堆栈更上层字符串的指针的开始; envp
(POSIX 机器上main()
的可选第三个参数)与全局变量environ
和argv[argc+1]
相同,也是一系列指向堆栈上方字符串的指针的开始; argv
和 envp
指针指向的字符串跟在这两个数组后面。
这是 Mac OS X 上的布局(10.7.5,如果重要,它可能不重要),但我可以肯定你会在其他类 Unix 系统上找到相同的布局。
【讨论】:
首先感谢您的回答。我已经研究了类 Unix 操作系统中进程的堆栈布局。但我想知道为什么 LD_PRELOAD 值在两个地方:在环境和堆栈的某个地方。第一个的格式为“LD_PRELOAD=xxxxxx”,但第二个的格式为“???xxxxxxx”,其中???是无法识别的字符串。我不关注环境或 argv[argc+1]。你怎么看待这件事?我是否遗漏或误解了什么?environ
的数据与堆栈位于同一区域,因此在堆栈中看到 LD_PRELOAD
并不奇怪。堆栈也可能已被ld.so.1
代码使用,它可能已将$LD_PRELOAD
的字符串值复制到堆栈上的缓冲区中,并且该信息可能尚未被覆盖。在这种情况下,巧合的是,来自$LD_PRELOAD
的数据两次在“堆栈”上,一次是存储环境的位置,一次是动态加载器复制它的位置。
好的。然后 LD_PRELOAD 的值可能会被动态加载器复制。唔。它仍然很奇怪,但我可以得到一些提示。我必须阅读动态加载器的源代码。谢谢。这很有帮助。以上是关于为啥堆栈上的LD_PRELOAD的值的主要内容,如果未能解决你的问题,请参考以下文章