What parts of a process' virtual address space are overwriteable?
For instance, lets suppose that instead of buffers growing in the opposite direction of the stack, they grow in the same direction. If I have a character buffer containing the string "Hello world", instead of 'H' being placed at the lowest address, it is placed at the highest address, and so on.
If an input string copied to a buffer were to overflow it could not overwrite the return address of the function, but certainly there are other things it could overwrite. My question is -- if the input string was long enough, what things could be overwritten? Are there library functions that exist between the heap and the stack that could be overwritten? Can heap variables be overwritten? I assume that variables in the data and bss sections can be overwritten, but is the text segment protected from writes?
The layout of processes in memory varies from system to system. This answer covers Linux under x86_64 processors.
There is a nice article illustrating the memory layout for Linux processes here.
If the buffer is a local variable, then it will be on the stack, along with other local variables. The first thing you are likely to hit if you overflow the buffer is other local variables in the same function.
When you reach the end of the stack, there is a randomly sized offset before the next used segment of memory. If you continue writing into this address space you would trigger a segfault (since that address space is not mapped to any physical RAM).
Assuming you managed to skip over the random offset without crashing, and continued overwriting, the next thing it might hit is the memory mapping segment. This segment contains file mappings, including those used to map dynamic shared libraries into the address space, and anonymous mappings. The dynamic libraries are going to be read-only, but if the process had any RW mappings in place you could perhaps overwrite data in them.
After this segment comes another random offset before you hit the heap. Again if you tried to write into the address space of the random offset you would trigger a crash.
Below the heap comes another random offset, followed by the BSS, Data and finally text segments. Static variables within BSS and Data could be overwritten. The text segment should not be writable.
You can inspect the memory map of a process using the pmap command.
The answer to your question depends entirely on what operating system is being used, as well as what hardware architecture. The operating system lays out logical memory in a certain fashion, and the architecture sometimes reserves (very low) memory for specific purposes as well.
One thing to understand is that traditional processes can access their entire logical memory space, but very little of this capacity is typically used. The most likely effect of what you describe is that you'll try to access some unallocated memory and you'll get a segfault in response, crashing your program.
That said, you definitely can modify these other segments of memory, but what happens when you do so depends on their read/write permissions. For example, the typical memory layout you learn in school is:
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
The .text segment is marked read only / executable by default, so if you attempt to write to a .text memory location you'll get a segmentation fault. It's possible to change .text to writeable, but this is in general a terrible idea.
The .data, .bss, .heap, and .stack segments are all readable/writeable by default, so you can overwrite those sections without any program errors.
The memory map segment(s) all have their own permissions to deal with as well. Some of these segments are writeable, most are not (so writing to them creates segfaults).
The last thing to note is that most modern OSes will randomize the locations of these segments to make things more difficult for hackers. This may introduce gaps between different segments (which will again cause segfaults if you try to access them).
On Linux, you can print out a process' memory map with the command pmap
. The following is the output of this program on an instance of 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
The segment starting at 0x851000 is actually the start of the heap (which pmap will tell you with more verbose reporting modes, but the more verbose mode didn't fit).
I think your question reflects a fundamental misunderstanding of how things work in an operating system. Things like "buffers" and "stack" tend not to be defined by the operating system.
The operating system divides memory into kernel and user areas (and some systems have additional, protected areas).
The layout of the user area is usually defined by the linker. The linker creates executables that instruct the loader how to set up the address space. Various linkers have different levels of control. Generally, the default linker settings group the sections of program as something like:
-Read/execute
-Read/no execute
-Read/write/initialized
-Read/write/demand zero
One some linkers you can create multiple program sections with these attributes.
You ask:
"If I have a character buffer containing the string "Hello world", instead of 'H' being placed at the lowest address, it is placed at the highest address, and so on."
In a van neumann machine, memory is independent of its usage. The same memory block can simultaneously be interpreted as a string, floating point, integer, or instruction. You can put your letter in any order you want but most software libraries would not recognize them in reverse order. IF your own libraries can handle the strings stored backwards, knock yourself out.
"My question is -- if the input string was long enough, what things could be overwritten?"
It could be anything.
"Are there library functions that exist between the heap and the stack that could be overwritten?"
That depends upon what your linker did.
"Can heap variables be overwritten?"
Heap can be overwritten.
"I assume that variables in the data and bss sections can be overwritten, but is the text segment protected from writes?
Generally, yes.
链接地址: http://www.djcxy.com/p/80248.html上一篇: 堆栈限制和线程之间的关系
下一篇: 进程的虚拟地址空间的哪些部分是可覆盖的?