进程的虚拟地址空间的哪些部分是可覆盖的?
例如,让我们假设,而不是缓冲区在堆栈的相反方向上生长,而是沿着相同的方向增长。 如果我有一个包含字符串“Hello world”的字符缓冲区,而不是将“H”放置在最低地址处,则将其放置在最高地址处,依此类推。
如果复制到缓冲区的输入字符串溢出,它不能覆盖该函数的返回地址,但肯定还有其他东西可以覆盖。 我的问题是 - 如果输入的字符串足够长,什么东西可以被覆盖? 堆和堆栈之间是否存在可被覆盖的库函数? 堆变量可以被覆盖吗? 我假设数据和bss部分中的变量可以被覆盖,但文本段是否被写入保护?
内存中进程的布局因系统而异。 这个答案涵盖了x86_64处理器下的Linux。
这里有一篇很好的文章来说明Linux进程的内存布局。
如果缓冲区是局部变量,那么它将与其他局部变量一起位于堆栈上。 如果溢出缓冲区,可能会遇到的第一件事是同一函数中的其他局部变量。
当到达堆栈的末尾时,在下一个使用的内存段之前有一个随机大小的偏移量。 如果您继续写入此地址空间,则会触发段错误(因为该地址空间未映射到任何物理RAM)。
假设你设法跳过了随机偏移而没有崩溃,并继续覆盖,它可能会遇到的下一件事是内存映射段。 该段包含文件映射,包括用于将动态共享库映射到地址空间的映射,以及匿名映射。 动态库将是只读的,但如果进程有任何RW映射,您可以覆盖它们中的数据。
在此段之后出现另一个随机偏移量,然后再点击堆。 同样,如果您尝试写入随机偏移的地址空间,您将触发崩溃。
堆下面是另一个随机偏移量,其次是BSS,数据,最后是文本段。 BSS和数据中的静态变量可以被覆盖。 文本段不应该是可写的。
您可以使用pmap命令检查进程的内存映射。
您的问题的答案完全取决于正在使用的操作系统以及硬件架构。 操作系统以某种方式布置逻辑内存,并且架构有时也为特定目的保留(非常低)内存。
有一点需要理解的是传统进程可以访问他们的整个逻辑内存空间,但通常使用的容量很小。 你所描述的最可能的影响是,你将尝试访问一些未分配的内存,你会得到一个段错误的响应,并导致程序崩溃。
也就是说,你一定可以修改这些其他的内存段,但是当你这样做的时候会发生什么,这取决于他们的读/写权限。 例如,您在学校学习的典型内存布局是:
Low memory to high memory:
.text - program code
.data - initialized static variables
.bss - uninitialized static variables
.heap - grows up
memory map segments - dynamic libraries
.stack - grows down
.text段默认标记为只读/可执行文件,因此如果您尝试写入.text内存位置,则会出现段错误。 可以将.text改为可写,但这通常是一个可怕的想法。
.data,.bss,.heap和.stack段默认都是可读/可写的,因此您可以在没有任何程序错误的情况下覆盖这些段。
内存映射段也都有自己的权限来处理。 其中一些片段是可写的,大多数不是(写入他们创建段错误)。
最后需要注意的是,大多数现代操作系统会随机分配这些部分的位置,以使黑客更加困难。 这可能会在不同的细分市场之间产生差距(如果您尝试访问它们,这将再次导致段错误)。
在Linux上,您可以使用命令pmap
打印进程的内存映射。 以下是该程序在vim实例上的输出:
10636: vim hello.text
0000000000400000 2112K r-x-- vim
000000000080f000 4K r---- vim
0000000000810000 88K rw--- vim
0000000000826000 56K rw--- [ anon ]
0000000000851000 2228K rw--- [ anon ]
00007f7df24c6000 8212K r--s- passwd
00007f7df2ccb000 32K r-x-- libnss_sss.so.2
00007f7df2cd3000 2044K ----- libnss_sss.so.2
00007f7df2ed2000 4K r---- libnss_sss.so.2
00007f7df2ed3000 4K rw--- libnss_sss.so.2
00007f7df2ed4000 48K r-x-- libnss_files-2.17.so
00007f7df2ee0000 2044K ----- libnss_files-2.17.so
00007f7df30df000 4K r---- libnss_files-2.17.so
00007f7df30e0000 4K rw--- libnss_files-2.17.so
00007f7df30e1000 24K rw--- [ anon ]
00007f7df30e7000 103580K r---- locale-archive
00007f7df960e000 8K r-x-- libfreebl3.so
00007f7df9610000 2044K ----- libfreebl3.so
00007f7df980f000 4K r---- libfreebl3.so
00007f7df9810000 4K rw--- libfreebl3.so
00007f7df9811000 8K r-x-- libutil-2.17.so
00007f7df9813000 2044K ----- libutil-2.17.so
00007f7df9a12000 4K r---- libutil-2.17.so
00007f7df9a13000 4K rw--- libutil-2.17.so
00007f7df9a14000 32K r-x-- libcrypt-2.17.so
00007f7df9a1c000 2044K ----- libcrypt-2.17.so
00007f7df9c1b000 4K r---- libcrypt-2.17.so
00007f7df9c1c000 4K rw--- libcrypt-2.17.so
00007f7df9c1d000 184K rw--- [ anon ]
00007f7df9c4b000 88K r-x-- libnsl-2.17.so
00007f7df9c61000 2044K ----- libnsl-2.17.so
00007f7df9e60000 4K r---- libnsl-2.17.so
00007f7df9e61000 4K rw--- libnsl-2.17.so
00007f7df9e62000 8K rw--- [ anon ]
00007f7df9e64000 88K r-x-- libresolv-2.17.so
00007f7df9e7a000 2048K ----- libresolv-2.17.so
00007f7dfa07a000 4K r---- libresolv-2.17.so
00007f7dfa07b000 4K rw--- libresolv-2.17.so
00007f7dfa07c000 8K rw--- [ anon ]
00007f7dfa07e000 152K r-x-- libncurses.so.5.9
00007f7dfa0a4000 2044K ----- libncurses.so.5.9
00007f7dfa2a3000 4K r---- libncurses.so.5.9
00007f7dfa2a4000 4K rw--- libncurses.so.5.9
00007f7dfa2a5000 16K r-x-- libattr.so.1.1.0
00007f7dfa2a9000 2044K ----- libattr.so.1.1.0
00007f7dfa4a8000 4K r---- libattr.so.1.1.0
00007f7dfa4a9000 4K rw--- libattr.so.1.1.0
00007f7dfa4aa000 144K r-x-- liblzma.so.5.0.99
00007f7dfa4ce000 2044K ----- liblzma.so.5.0.99
00007f7dfa6cd000 4K r---- liblzma.so.5.0.99
00007f7dfa6ce000 4K rw--- liblzma.so.5.0.99
00007f7dfa6cf000 384K r-x-- libpcre.so.1.2.0
00007f7dfa72f000 2044K ----- libpcre.so.1.2.0
00007f7dfa92e000 4K r---- libpcre.so.1.2.0
00007f7dfa92f000 4K rw--- libpcre.so.1.2.0
00007f7dfa930000 1756K r-x-- libc-2.17.so
00007f7dfaae7000 2048K ----- libc-2.17.so
00007f7dface7000 16K r---- libc-2.17.so
00007f7dfaceb000 8K rw--- libc-2.17.so
00007f7dfaced000 20K rw--- [ anon ]
00007f7dfacf2000 88K r-x-- libpthread-2.17.so
00007f7dfad08000 2048K ----- libpthread-2.17.so
00007f7dfaf08000 4K r---- libpthread-2.17.so
00007f7dfaf09000 4K rw--- libpthread-2.17.so
00007f7dfaf0a000 16K rw--- [ anon ]
00007f7dfaf0e000 1548K r-x-- libperl.so
00007f7dfb091000 2044K ----- libperl.so
00007f7dfb290000 16K r---- libperl.so
00007f7dfb294000 24K rw--- libperl.so
00007f7dfb29a000 4K rw--- [ anon ]
00007f7dfb29b000 12K r-x-- libdl-2.17.so
00007f7dfb29e000 2044K ----- libdl-2.17.so
00007f7dfb49d000 4K r---- libdl-2.17.so
00007f7dfb49e000 4K rw--- libdl-2.17.so
00007f7dfb49f000 20K r-x-- libgpm.so.2.1.0
00007f7dfb4a4000 2048K ----- libgpm.so.2.1.0
00007f7dfb6a4000 4K r---- libgpm.so.2.1.0
00007f7dfb6a5000 4K rw--- libgpm.so.2.1.0
00007f7dfb6a6000 28K r-x-- libacl.so.1.1.0
00007f7dfb6ad000 2048K ----- libacl.so.1.1.0
00007f7dfb8ad000 4K r---- libacl.so.1.1.0
00007f7dfb8ae000 4K rw--- libacl.so.1.1.0
00007f7dfb8af000 148K r-x-- libtinfo.so.5.9
00007f7dfb8d4000 2048K ----- libtinfo.so.5.9
00007f7dfbad4000 16K r---- libtinfo.so.5.9
00007f7dfbad8000 4K rw--- libtinfo.so.5.9
00007f7dfbad9000 132K r-x-- libselinux.so.1
00007f7dfbafa000 2048K ----- libselinux.so.1
00007f7dfbcfa000 4K r---- libselinux.so.1
00007f7dfbcfb000 4K rw--- libselinux.so.1
00007f7dfbcfc000 8K rw--- [ anon ]
00007f7dfbcfe000 1028K r-x-- libm-2.17.so
00007f7dfbdff000 2044K ----- libm-2.17.so
00007f7dfbffe000 4K r---- libm-2.17.so
00007f7dfbfff000 4K rw--- libm-2.17.so
00007f7dfc000000 132K r-x-- ld-2.17.so
00007f7dfc1f8000 40K rw--- [ anon ]
00007f7dfc220000 4K rw--- [ anon ]
00007f7dfc221000 4K r---- ld-2.17.so
00007f7dfc222000 4K rw--- ld-2.17.so
00007f7dfc223000 4K rw--- [ anon ]
00007ffcb46e7000 132K rw--- [ stack ]
00007ffcb475f000 8K r-x-- [ anon ]
ffffffffff600000 4K r-x-- [ anon ]
total 163772K
从0x851000开始的段实际上是堆的开始(pmap会告诉你更详细的报告模式,但更详细的模式不适合)。
我认为你的问题反映了对操作系统中的事情如何工作的根本性误解。 像“缓冲区”和“堆栈”之类的东西往往不会被操作系统定义。
操作系统将内存划分为内核和用户区域(有些系统还有额外的受保护区域)。
用户区的布局通常由链接器定义。 链接器创建可执行文件,指示加载程序如何设置地址空间。 各种连接器具有不同的控制水平。 通常,默认链接器设置将程序的各个部分分组为如下所示的内容:
- 读取/执行
- 读/不执行
- 读取/写入/初始化
- 读/写/需求零
一些连接器可以用这些属性创建多个程序段。
你问:
“如果我有一个包含字符串”Hello world“的字符缓冲区,而不是将”H“放置在最低地址处,则将其放置在最高地址处,等等。”
在范诺伊曼机器中,内存与其使用无关。 同一个内存块可以同时被解释为一个字符串,浮点数,整数或指令。 你可以按你想要的顺序放置你的信件,但大多数软件库不会以相反的顺序识别它们。 如果你自己的图书馆可以处理向后存储的字符串,请自行解决。
“我的问题是 - 如果输入的字符串足够长,什么东西可以被覆盖?”
它可能是任何东西。
“堆和堆栈之间是否存在可被覆盖的库函数?”
这取决于你的链接器做了什么。
“堆变量可以被覆盖吗?”
堆可以被覆盖。
“我假设数据和bss部分中的变量可以被覆盖,但文本段受到写保护吗?
一般来说,是的。
链接地址: http://www.djcxy.com/p/80247.html上一篇: What parts of a process' virtual address space are overwriteable?