In the way to understanding binaries (Virtual memory layout, execution...etc), I've written a C
code that declares a global string which contains bytes of an executable code, then i overwrote the return address from the main()
function to that executable code using a simple trick by declaring a pointer (PTR
) in main()
which is a local area of memory reserved on the stack 2 WORDS far away from the return address from the main()
, so all i do is assigning the address of the return address to that pointer (PTR=(int*)&PTR+2)
and then overwrite the content of that address with the address of the executable code (the static string).
Now the dilemma is that, whenever i compile and i execute, i receive a segmentation fault.
The executable code does no memory input/output
(its just a bunch of NOPs
).
Using GDB i made sure that the process works perfectly: the return address is changed to be the string's address but the return never happens.
All i know is that the executable code is mapped to pages in virtual memory thar are marked RW
(.data
& .bss
segments) so maybe there's no way to do such a code execution unless code is injected in an executable
area of memory (Pages that are marked RE
). That's my theory about the subject, i invite you to give more details.
char code[]="\x90\x90\x90\x90\x90\x90\x90\x90"; //a static string contains executable code
int main()
{
int *return_address; //Pointer to the return address - uninitialized
return_address = (int *)&return_address + 2; //Initializing the return address - according to stack layout
(*return_address) = (int)code; //Overwriting the return address with the code's address
}
i receive a segmentation fault.
It is hardware control of data execution prevention (https://en.wikipedia.org/wiki/Executable_space_protection#Linux) - you can't just jump to data page if it has no 'x' (execute) bit set in page tables. Memory mappings with all bits are listed in /proc/$pid/maps
/ /proc/$pid/smaps
files as 'rwx' for writable code, 'rw-' for data without execution, 'r--' for readonly data, 'r-x' for normal code.
If you want to execute data, you should call mprotect
syscall with PROT_EXEC
flag on the section of your data which wants to be code.
In x86 world this was fully implemented as "NX bit" / "XD bit" feature in Pentium 4 (Prescott) and newer (Core, Core2, Core i*, core m) / in Athlon 64 / Opteron and newer. If OS works in 32-bit mode, it must turn on PAE to have this bit in page table. In x86_64 mode (64-bit) there is always NX/XD bit supported.
First variants of support were added to linux around 2004: http://linuxgazette.net/107/pramode.html
In 2007 you may have outdated hardware, old kernel or 32-bit mode kernel without PAE.
Info about NX/XD bits: https://en.wikipedia.org/wiki/NX_bit
Sometimes 'rwx' mode may be prohibited, check https://en.wikipedia.org/wiki/W^X.
For pre-NX systems there were solutions based on segment registers of x86 to partially disable part of memory space from executing.
can i execute the program above without having an segmentation fault ?
You can:
- make the data page executable by calling
mprotect
on it with PROT_READ|PROT_EXEC
- make the data segment of elf file marked as executable (need to hack deeply inside
ld
scripts - default is in ld --verbose
)
- make all pages including
.data
and the heap executable (not just the stack)
with ld or gcc -z execstack
- move shellcode to text data of elf file
- try to disable nx/xd bit in kernel (hard; recompilation may be needed)
- use 32-bit OS (kernel) without PAE option enabled (build time option).
- use older cpu without NX/XD